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 int 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 int 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 int 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 int i, j; 714 715 for (j = 1; j < size; j++) { 716 int key = idlist[j]; 717 for (i = j - 1; (i >= 0) && (idlist[i] > key); i--) 718 idlist[i + 1] = idlist[i]; 719 idlist[i + 1] = key; 720 } 721 } 722 723 /* Support for legacy drivers */ 724 void 725 i_query_legacy_stats(dladm_handle_t dh, const char *linkname, pktsum_t *stats) 726 { 727 kstat_t *ksp; 728 729 bzero(stats, sizeof (*stats)); 730 731 if (dladm_dld_kcp(dh) == NULL) 732 return; 733 734 ksp = dladm_kstat_lookup(dladm_dld_kcp(dh), "link", 0, linkname, NULL); 735 736 if (ksp != NULL) 737 dladm_get_stats(dladm_dld_kcp(dh), ksp, stats); 738 } 739 740 void * 741 i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh, const char *linkname) 742 { 743 dladm_stat_chain_t *head = NULL; 744 pktsum_t stats; 745 rx_lane_stat_entry_t *rx_lane_stat_entry; 746 747 bzero(&stats, sizeof (pktsum_t)); 748 749 /* Query for dls stats */ 750 i_query_legacy_stats(dh, linkname, &stats); 751 752 /* Convert to desired data type */ 753 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 754 if (rx_lane_stat_entry == NULL) 755 goto done; 756 757 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 758 rx_lane_stat_entry->rle_id = L_SWLANE; 759 760 rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets; 761 rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets; 762 rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes; 763 764 /* Allocate memory for wrapper */ 765 head = malloc(sizeof (dladm_stat_chain_t)); 766 if (head == NULL) { 767 free(rx_lane_stat_entry); 768 goto done; 769 } 770 771 head->dc_statentry = rx_lane_stat_entry; 772 head->dc_next = NULL; 773 done: 774 return (head); 775 } 776 777 void * 778 i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh, const char *linkname) 779 { 780 dladm_stat_chain_t *head = NULL; 781 pktsum_t stats; 782 tx_lane_stat_entry_t *tx_lane_stat_entry; 783 784 bzero(&stats, sizeof (pktsum_t)); 785 786 /* Query for dls stats */ 787 i_query_legacy_stats(dh, linkname, &stats); 788 789 /* Convert to desired data type */ 790 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 791 if (tx_lane_stat_entry == NULL) 792 goto done; 793 794 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 795 tx_lane_stat_entry->tle_id = L_SWLANE; 796 797 tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets; 798 tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes; 799 800 /* Allocate memory for wrapper */ 801 head = malloc(sizeof (dladm_stat_chain_t)); 802 if (head == NULL) { 803 free(tx_lane_stat_entry); 804 goto done; 805 } 806 807 head->dc_statentry = tx_lane_stat_entry; 808 head->dc_next = NULL; 809 done: 810 return (head); 811 } 812 813 /* 814 * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids) 815 * for a given data-link (or mac client). We could then query for specific 816 * kstats based on these ring-ids (lane-ids). 817 * Ring-ids (or lane-ids) could be returned like any other link properties 818 * queried by dladm show-linkprop. However, non-global zones do not have 819 * access to this information today. 820 * We thus opt for an implementation that relies heavily on kstat internals: 821 * i_dlstat_*search routines and i_dlstat_get_idlist. 822 */ 823 /* rx hwlane specific */ 824 static boolean_t 825 i_dlstat_rx_hwlane_search(kstat_t *ksp) 826 { 827 return (ksp->ks_instance == 0 && 828 strstr(ksp->ks_name, "mac_rx") != 0 && 829 strstr(ksp->ks_name, "hwlane") != 0 && 830 strstr(ksp->ks_name, "fanout") == 0 && 831 strcmp(ksp->ks_class, "net") == 0); 832 } 833 834 /* tx hwlane specific */ 835 static boolean_t 836 i_dlstat_tx_hwlane_search(kstat_t *ksp) 837 { 838 return (ksp->ks_instance == 0 && 839 strstr(ksp->ks_name, "mac_tx") != 0 && 840 strstr(ksp->ks_name, "hwlane") != 0 && 841 strcmp(ksp->ks_class, "net") == 0); 842 } 843 844 /* rx fanout specific */ 845 static boolean_t 846 i_dlstat_fanout_search(kstat_t *ksp) 847 { 848 return (ksp->ks_instance == 0 && 849 strstr(ksp->ks_name, "mac_rx") != 0 && 850 strstr(ksp->ks_name, "swlane") != 0 && 851 strstr(ksp->ks_name, "fanout") != 0 && 852 strcmp(ksp->ks_class, "net") == 0); 853 } 854 855 /* rx ring specific */ 856 static boolean_t 857 i_dlstat_rx_ring_search(kstat_t *ksp) 858 { 859 return (ksp->ks_instance == 0 && 860 strstr(ksp->ks_name, "mac_rx") != 0 && 861 strstr(ksp->ks_name, "ring") != 0 && 862 strcmp(ksp->ks_class, "net") == 0); 863 } 864 865 /* tx ring specific */ 866 static boolean_t 867 i_dlstat_tx_ring_search(kstat_t *ksp) 868 { 869 return (ksp->ks_instance == 0) && 870 strstr(ksp->ks_name, "mac_tx") != 0 && 871 strstr(ksp->ks_name, "ring") != 0 && 872 strcmp(ksp->ks_class, "net") == 0; 873 } 874 875 typedef boolean_t dladm_search_kstat_t(kstat_t *); 876 typedef struct dladm_extract_idlist_s { 877 dlstat_idlist_type_t di_type; 878 char *di_prefix; 879 dladm_search_kstat_t *di_searchkstat; 880 } dladm_extract_idlist_t; 881 882 static dladm_extract_idlist_t dladm_extract_idlist[] = { 883 { DLSTAT_RX_RING_IDLIST, DLSTAT_MAC_RX_RING, 884 i_dlstat_rx_ring_search}, 885 { DLSTAT_TX_RING_IDLIST, DLSTAT_MAC_TX_RING, 886 i_dlstat_tx_ring_search}, 887 { DLSTAT_RX_HWLANE_IDLIST, DLSTAT_MAC_RX_HWLANE, 888 i_dlstat_rx_hwlane_search}, 889 { DLSTAT_TX_HWLANE_IDLIST, DLSTAT_MAC_TX_HWLANE, 890 i_dlstat_tx_hwlane_search}, 891 { DLSTAT_FANOUT_IDLIST, DLSTAT_MAC_FANOUT, 892 i_dlstat_fanout_search} 893 }; 894 895 static void 896 i_dlstat_get_idlist(dladm_handle_t handle, const char *modname, 897 dlstat_idlist_type_t idlist_type, 898 uint_t idlist[], uint_t *size) 899 { 900 kstat_ctl_t *kcp = dladm_dld_kcp(handle); 901 kstat_t *ksp; 902 char *prefix; 903 int prefixlen; 904 boolean_t (*fptr_searchkstat)(kstat_t *); 905 906 *size = 0; 907 908 if (kcp == NULL) { 909 warn("kstat_open operation failed"); 910 return; 911 } 912 913 prefix = dladm_extract_idlist[idlist_type].di_prefix; 914 fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat; 915 prefixlen = strlen(prefix); 916 for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 917 if ((strcmp(ksp->ks_module, modname) == 0) && 918 fptr_searchkstat(ksp)) { 919 idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]); 920 } 921 } 922 dladm_sort_index_list(idlist, *size); 923 } 924 925 static dladm_stat_chain_t * 926 i_dlstat_query_stats(dladm_handle_t handle, const char *modname, 927 const char *prefix, uint_t idlist[], uint_t idlist_size, 928 void * (*fn)(kstat_ctl_t *, kstat_t *, int)) 929 { 930 kstat_t *ksp; 931 char statname[MAXLINKNAMELEN]; 932 int i = 0; 933 dladm_stat_chain_t *head = NULL, *prev = NULL; 934 dladm_stat_chain_t *curr; 935 936 if (dladm_dld_kcp(handle) == NULL) { 937 warn("kstat_open operation failed"); 938 return (NULL); 939 } 940 941 for (i = 0; i < idlist_size; i++) { 942 uint_t index = idlist[i]; 943 944 (void) snprintf(statname, sizeof (statname), "%s%d", prefix, 945 index); 946 947 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), modname, 0, 948 statname, NULL); 949 if (ksp == NULL) 950 continue; 951 952 curr = malloc(sizeof (dladm_stat_chain_t)); 953 if (curr == NULL) 954 break; 955 956 curr->dc_statentry = fn(dladm_dld_kcp(handle), ksp, index); 957 if (curr->dc_statentry == NULL) { 958 free(curr); 959 break; 960 } 961 962 (void) strlcpy(curr->dc_statheader, statname, 963 sizeof (curr->dc_statheader)); 964 curr->dc_next = NULL; 965 966 if (head == NULL) /* First node */ 967 head = curr; 968 else 969 prev->dc_next = curr; 970 971 prev = curr; 972 } 973 return (head); 974 } 975 976 static misc_stat_entry_t * 977 i_dlstat_misc_stats(dladm_handle_t handle, const char *linkname) 978 { 979 kstat_t *ksp; 980 misc_stat_entry_t *misc_stat_entry = NULL; 981 982 if (dladm_dld_kcp(handle) == NULL) 983 return (NULL); 984 985 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), linkname, 0, 986 DLSTAT_MAC_MISC_STAT, NULL); 987 if (ksp == NULL) 988 goto done; 989 990 misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t)); 991 if (misc_stat_entry == NULL) 992 goto done; 993 994 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, 995 &misc_stat_entry->mse_stats, 996 misc_stats_list, MISC_STAT_SIZE); 997 done: 998 return (misc_stat_entry); 999 } 1000 1001 /* Rx lane statistic specific functions */ 1002 static boolean_t 1003 i_dlstat_rx_lane_match(void *arg1, void *arg2) 1004 { 1005 rx_lane_stat_entry_t *s1 = arg1; 1006 rx_lane_stat_entry_t *s2 = arg2; 1007 1008 return (s1->rle_index == s2->rle_index && 1009 s1->rle_id == s2->rle_id); 1010 } 1011 1012 static void * 1013 i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2) 1014 { 1015 rx_lane_stat_entry_t *s1 = arg1; 1016 rx_lane_stat_entry_t *s2 = arg2; 1017 rx_lane_stat_entry_t *diff_entry; 1018 1019 diff_entry = malloc(sizeof (rx_lane_stat_entry_t)); 1020 if (diff_entry == NULL) 1021 goto done; 1022 1023 diff_entry->rle_index = s1->rle_index; 1024 diff_entry->rle_id = s1->rle_id; 1025 1026 DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list, 1027 RX_LANE_STAT_SIZE); 1028 1029 done: 1030 return (diff_entry); 1031 } 1032 1033 static void * 1034 i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1035 { 1036 rx_lane_stat_entry_t *rx_lane_stat_entry; 1037 1038 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1039 if (rx_lane_stat_entry == NULL) 1040 goto done; 1041 1042 rx_lane_stat_entry->rle_index = i; 1043 rx_lane_stat_entry->rle_id = L_HWLANE; 1044 1045 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1046 rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE); 1047 1048 done: 1049 return (rx_lane_stat_entry); 1050 } 1051 1052 static void * 1053 i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused) 1054 { 1055 rx_lane_stat_entry_t *rx_lane_stat_entry; 1056 1057 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1058 if (rx_lane_stat_entry == NULL) 1059 goto done; 1060 1061 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1062 rx_lane_stat_entry->rle_id = L_SWLANE; 1063 1064 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1065 rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 1066 1067 rx_lane_stat_entry->rle_stats.rl_ipackets = 1068 rx_lane_stat_entry->rle_stats.rl_intrs; 1069 rx_lane_stat_entry->rle_stats.rl_rbytes = 1070 rx_lane_stat_entry->rle_stats.rl_intrbytes; 1071 done: 1072 return (rx_lane_stat_entry); 1073 } 1074 1075 static void * 1076 i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused) 1077 { 1078 rx_lane_stat_entry_t *local_stat_entry = NULL; 1079 rx_lane_stat_entry_t *rx_lane_stat_entry; 1080 1081 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1082 if (rx_lane_stat_entry == NULL) 1083 goto done; 1084 1085 local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1086 if (local_stat_entry == NULL) 1087 goto done; 1088 1089 local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1090 local_stat_entry->rle_id = L_LOCAL; 1091 1092 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1093 rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 1094 1095 local_stat_entry->rle_stats.rl_ipackets = 1096 rx_lane_stat_entry->rle_stats.rl_lclpackets; 1097 local_stat_entry->rle_stats.rl_rbytes = 1098 rx_lane_stat_entry->rle_stats.rl_lclbytes; 1099 1100 done: 1101 free(rx_lane_stat_entry); 1102 return (local_stat_entry); 1103 } 1104 1105 static dladm_stat_chain_t * 1106 i_dlstat_rx_local_stats(dladm_handle_t handle, const char *linkname) 1107 { 1108 dladm_stat_chain_t *local_stats = NULL; 1109 1110 local_stats = i_dlstat_query_stats(handle, linkname, 1111 DLSTAT_MAC_RX_SWLANE, 1112 default_idlist, default_idlist_size, 1113 i_dlstat_rx_local_retrieve_stat); 1114 1115 if (local_stats != NULL) { 1116 (void) strlcpy(local_stats->dc_statheader, "mac_rx_local", 1117 sizeof (local_stats->dc_statheader)); 1118 } 1119 return (local_stats); 1120 } 1121 1122 static dladm_stat_chain_t * 1123 i_dlstat_rx_bcast_stats(dladm_handle_t handle, const char *linkname) 1124 { 1125 misc_stat_entry_t *misc_stat_entry; 1126 dladm_stat_chain_t *head = NULL; 1127 rx_lane_stat_entry_t *rx_lane_stat_entry; 1128 1129 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1130 if (misc_stat_entry == NULL) 1131 goto done; 1132 1133 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1134 if (rx_lane_stat_entry == NULL) 1135 goto done; 1136 1137 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1138 rx_lane_stat_entry->rle_id = L_BCAST; 1139 1140 rx_lane_stat_entry->rle_stats.rl_ipackets = 1141 misc_stat_entry->mse_stats.ms_brdcstrcv + 1142 misc_stat_entry->mse_stats.ms_multircv; 1143 rx_lane_stat_entry->rle_stats.rl_intrs = 1144 misc_stat_entry->mse_stats.ms_brdcstrcv + 1145 misc_stat_entry->mse_stats.ms_multircv; 1146 rx_lane_stat_entry->rle_stats.rl_rbytes = 1147 misc_stat_entry->mse_stats.ms_brdcstrcvbytes + 1148 misc_stat_entry->mse_stats.ms_multircvbytes; 1149 1150 head = malloc(sizeof (dladm_stat_chain_t)); 1151 if (head == NULL) { 1152 free(rx_lane_stat_entry); 1153 goto done; 1154 } 1155 1156 head->dc_statentry = rx_lane_stat_entry; 1157 head->dc_next = NULL; 1158 1159 free(misc_stat_entry); 1160 done: 1161 return (head); 1162 } 1163 1164 static dladm_stat_chain_t * 1165 i_dlstat_rx_defunctlane_stats(dladm_handle_t handle, const char *linkname) 1166 { 1167 misc_stat_entry_t *misc_stat_entry; 1168 dladm_stat_chain_t *head = NULL; 1169 rx_lane_stat_entry_t *rx_lane_stat_entry; 1170 1171 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1172 if (misc_stat_entry == NULL) 1173 goto done; 1174 1175 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1176 if (rx_lane_stat_entry == NULL) 1177 goto done; 1178 1179 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1180 rx_lane_stat_entry->rle_id = L_DFNCT; 1181 1182 rx_lane_stat_entry->rle_stats.rl_ipackets = 1183 misc_stat_entry->mse_stats.ms_ipackets; 1184 rx_lane_stat_entry->rle_stats.rl_rbytes = 1185 misc_stat_entry->mse_stats.ms_rbytes; 1186 rx_lane_stat_entry->rle_stats.rl_intrs = 1187 misc_stat_entry->mse_stats.ms_intrs; 1188 rx_lane_stat_entry->rle_stats.rl_polls = 1189 misc_stat_entry->mse_stats.ms_polls; 1190 rx_lane_stat_entry->rle_stats.rl_sdrops = 1191 misc_stat_entry->mse_stats.ms_rxsdrops; 1192 rx_lane_stat_entry->rle_stats.rl_chl10 = 1193 misc_stat_entry->mse_stats.ms_chainunder10; 1194 rx_lane_stat_entry->rle_stats.rl_ch10_50 = 1195 misc_stat_entry->mse_stats.ms_chain10to50; 1196 rx_lane_stat_entry->rle_stats.rl_chg50 = 1197 misc_stat_entry->mse_stats.ms_chainover50; 1198 1199 head = malloc(sizeof (dladm_stat_chain_t)); 1200 if (head == NULL) { 1201 free(rx_lane_stat_entry); 1202 goto done; 1203 } 1204 1205 head->dc_statentry = rx_lane_stat_entry; 1206 head->dc_next = NULL; 1207 1208 done: 1209 return (head); 1210 } 1211 1212 static dladm_stat_chain_t * 1213 i_dlstat_rx_hwlane_stats(dladm_handle_t handle, const char *linkname) 1214 { 1215 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1216 uint_t rx_hwlane_idlist_size; 1217 1218 i_dlstat_get_idlist(handle, linkname, DLSTAT_RX_HWLANE_IDLIST, 1219 rx_hwlane_idlist, &rx_hwlane_idlist_size); 1220 1221 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_RX_HWLANE, 1222 rx_hwlane_idlist, rx_hwlane_idlist_size, 1223 i_dlstat_rx_hwlane_retrieve_stat)); 1224 } 1225 1226 static dladm_stat_chain_t * 1227 i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused, 1228 const char *linkname) 1229 { 1230 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_RX_SWLANE, 1231 default_idlist, default_idlist_size, 1232 i_dlstat_rx_swlane_retrieve_stat)); 1233 } 1234 1235 void * 1236 dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 1237 { 1238 dladm_stat_chain_t *head = NULL; 1239 dladm_stat_chain_t *local_stats = NULL; 1240 dladm_stat_chain_t *bcast_stats = NULL; 1241 dladm_stat_chain_t *defunctlane_stats = NULL; 1242 dladm_stat_chain_t *lane_stats = NULL; 1243 char linkname[MAXLINKNAMELEN]; 1244 boolean_t is_legacy_driver; 1245 1246 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1247 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1248 goto done; 1249 } 1250 1251 /* Check if it is legacy driver */ 1252 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 1253 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 1254 goto done; 1255 } 1256 1257 if (is_legacy_driver) { 1258 head = i_dlstat_legacy_rx_lane_stats(dh, linkname); 1259 goto done; 1260 } 1261 1262 local_stats = i_dlstat_rx_local_stats(dh, linkname); 1263 bcast_stats = i_dlstat_rx_bcast_stats(dh, linkname); 1264 defunctlane_stats = i_dlstat_rx_defunctlane_stats(dh, linkname); 1265 lane_stats = i_dlstat_rx_hwlane_stats(dh, linkname); 1266 if (lane_stats == NULL) 1267 lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname); 1268 1269 head = i_dlstat_join_lists(local_stats, bcast_stats); 1270 head = i_dlstat_join_lists(head, defunctlane_stats); 1271 head = i_dlstat_join_lists(head, lane_stats); 1272 done: 1273 return (head); 1274 } 1275 1276 /* Tx lane statistic specific functions */ 1277 static boolean_t 1278 i_dlstat_tx_lane_match(void *arg1, void *arg2) 1279 { 1280 tx_lane_stat_entry_t *s1 = arg1; 1281 tx_lane_stat_entry_t *s2 = arg2; 1282 1283 return (s1->tle_index == s2->tle_index && 1284 s1->tle_id == s2->tle_id); 1285 } 1286 1287 static void * 1288 i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2) 1289 { 1290 tx_lane_stat_entry_t *s1 = arg1; 1291 tx_lane_stat_entry_t *s2 = arg2; 1292 tx_lane_stat_entry_t *diff_entry; 1293 1294 diff_entry = malloc(sizeof (tx_lane_stat_entry_t)); 1295 if (diff_entry == NULL) 1296 goto done; 1297 1298 diff_entry->tle_index = s1->tle_index; 1299 diff_entry->tle_id = s1->tle_id; 1300 1301 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list, 1302 TX_LANE_STAT_SIZE); 1303 1304 done: 1305 return (diff_entry); 1306 } 1307 1308 static void * 1309 i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1310 { 1311 tx_lane_stat_entry_t *tx_lane_stat_entry; 1312 1313 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1314 if (tx_lane_stat_entry == NULL) 1315 goto done; 1316 1317 tx_lane_stat_entry->tle_index = i; 1318 tx_lane_stat_entry->tle_id = L_HWLANE; 1319 1320 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 1321 tx_lane_stats_list, TX_LANE_STAT_SIZE); 1322 1323 done: 1324 return (tx_lane_stat_entry); 1325 } 1326 1327 static void * 1328 i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused) 1329 { 1330 tx_lane_stat_entry_t *tx_lane_stat_entry; 1331 1332 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1333 if (tx_lane_stat_entry == NULL) 1334 goto done; 1335 1336 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1337 tx_lane_stat_entry->tle_id = L_SWLANE; 1338 1339 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 1340 tx_lane_stats_list, TX_LANE_STAT_SIZE); 1341 1342 done: 1343 return (tx_lane_stat_entry); 1344 } 1345 1346 static dladm_stat_chain_t * 1347 i_dlstat_tx_bcast_stats(dladm_handle_t handle, const char *linkname) 1348 { 1349 misc_stat_entry_t *misc_stat_entry; 1350 dladm_stat_chain_t *head = NULL; 1351 tx_lane_stat_entry_t *tx_lane_stat_entry; 1352 1353 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1354 if (misc_stat_entry == NULL) 1355 goto done; 1356 1357 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1358 if (tx_lane_stat_entry == NULL) 1359 goto done; 1360 1361 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1362 tx_lane_stat_entry->tle_id = L_BCAST; 1363 1364 tx_lane_stat_entry->tle_stats.tl_opackets = 1365 misc_stat_entry->mse_stats.ms_brdcstxmt + 1366 misc_stat_entry->mse_stats.ms_multixmt; 1367 1368 tx_lane_stat_entry->tle_stats.tl_obytes = 1369 misc_stat_entry->mse_stats.ms_brdcstxmtbytes + 1370 misc_stat_entry->mse_stats.ms_multixmtbytes; 1371 1372 head = malloc(sizeof (dladm_stat_chain_t)); 1373 if (head == NULL) { 1374 free(tx_lane_stat_entry); 1375 goto done; 1376 } 1377 1378 head->dc_statentry = tx_lane_stat_entry; 1379 head->dc_next = NULL; 1380 1381 free(misc_stat_entry); 1382 done: 1383 return (head); 1384 } 1385 1386 static dladm_stat_chain_t * 1387 i_dlstat_tx_defunctlane_stats(dladm_handle_t handle, const char *linkname) 1388 { 1389 misc_stat_entry_t *misc_stat_entry; 1390 dladm_stat_chain_t *head = NULL; 1391 tx_lane_stat_entry_t *tx_lane_stat_entry; 1392 1393 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1394 if (misc_stat_entry == NULL) 1395 goto done; 1396 1397 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1398 if (tx_lane_stat_entry == NULL) 1399 goto done; 1400 1401 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1402 tx_lane_stat_entry->tle_id = L_DFNCT; 1403 1404 tx_lane_stat_entry->tle_stats.tl_opackets = 1405 misc_stat_entry->mse_stats.ms_opackets; 1406 tx_lane_stat_entry->tle_stats.tl_obytes = 1407 misc_stat_entry->mse_stats.ms_obytes; 1408 tx_lane_stat_entry->tle_stats.tl_sdrops = 1409 misc_stat_entry->mse_stats.ms_txsdrops; 1410 1411 head = malloc(sizeof (dladm_stat_chain_t)); 1412 if (head == NULL) { 1413 free(tx_lane_stat_entry); 1414 goto done; 1415 } 1416 1417 head->dc_statentry = tx_lane_stat_entry; 1418 head->dc_next = NULL; 1419 1420 done: 1421 return (head); 1422 } 1423 1424 static dladm_stat_chain_t * 1425 i_dlstat_tx_hwlane_stats(dladm_handle_t handle, const char *linkname) 1426 { 1427 uint_t tx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1428 uint_t tx_hwlane_idlist_size; 1429 1430 i_dlstat_get_idlist(handle, linkname, DLSTAT_TX_HWLANE_IDLIST, 1431 tx_hwlane_idlist, &tx_hwlane_idlist_size); 1432 1433 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_TX_HWLANE, 1434 tx_hwlane_idlist, tx_hwlane_idlist_size, 1435 i_dlstat_tx_hwlane_retrieve_stat)); 1436 } 1437 1438 static dladm_stat_chain_t * 1439 i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused, 1440 const char *linkname) 1441 { 1442 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_TX_SWLANE, 1443 default_idlist, default_idlist_size, 1444 i_dlstat_tx_swlane_retrieve_stat)); 1445 } 1446 1447 void * 1448 dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 1449 { 1450 dladm_stat_chain_t *head = NULL; 1451 dladm_stat_chain_t *bcast_stats = NULL; 1452 dladm_stat_chain_t *defunctlane_stats = NULL; 1453 dladm_stat_chain_t *lane_stats; 1454 char linkname[MAXLINKNAMELEN]; 1455 boolean_t is_legacy_driver; 1456 1457 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1458 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1459 goto done; 1460 } 1461 1462 /* Check if it is legacy driver */ 1463 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 1464 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 1465 goto done; 1466 } 1467 1468 if (is_legacy_driver) { 1469 head = i_dlstat_legacy_tx_lane_stats(dh, linkname); 1470 goto done; 1471 } 1472 1473 bcast_stats = i_dlstat_tx_bcast_stats(dh, linkname); 1474 defunctlane_stats = i_dlstat_tx_defunctlane_stats(dh, linkname); 1475 lane_stats = i_dlstat_tx_hwlane_stats(dh, linkname); 1476 if (lane_stats == NULL) 1477 lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname); 1478 1479 head = i_dlstat_join_lists(bcast_stats, defunctlane_stats); 1480 head = i_dlstat_join_lists(head, lane_stats); 1481 1482 done: 1483 return (head); 1484 } 1485 1486 /* Rx lane total statistic specific functions */ 1487 void * 1488 dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1489 { 1490 dladm_stat_chain_t *total_head = NULL; 1491 dladm_stat_chain_t *rx_lane_head, *curr; 1492 rx_lane_stat_entry_t *total_stats; 1493 1494 /* Get per rx lane stats */ 1495 rx_lane_head = dlstat_rx_lane_stats(dh, linkid); 1496 if (rx_lane_head == NULL) 1497 goto done; 1498 1499 total_stats = calloc(1, sizeof (rx_lane_stat_entry_t)); 1500 if (total_stats == NULL) 1501 goto done; 1502 1503 total_stats->rle_index = DLSTAT_INVALID_ENTRY; 1504 total_stats->rle_id = DLSTAT_INVALID_ENTRY; 1505 1506 for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) { 1507 rx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 1508 1509 i_dlstat_sum_stats(&total_stats->rle_stats, 1510 &curr_lane_stats->rle_stats, &total_stats->rle_stats, 1511 rx_lane_stats_list, RX_LANE_STAT_SIZE); 1512 } 1513 1514 total_head = malloc(sizeof (dladm_stat_chain_t)); 1515 if (total_head == NULL) { 1516 free(total_stats); 1517 goto done; 1518 } 1519 1520 total_head->dc_statentry = total_stats; 1521 (void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total", 1522 sizeof (total_head->dc_statheader)); 1523 total_head->dc_next = NULL; 1524 free(rx_lane_head); 1525 1526 done: 1527 return (total_head); 1528 } 1529 1530 /* Tx lane total statistic specific functions */ 1531 void * 1532 dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1533 { 1534 dladm_stat_chain_t *total_head = NULL; 1535 dladm_stat_chain_t *tx_lane_head, *curr; 1536 tx_lane_stat_entry_t *total_stats; 1537 1538 /* Get per tx lane stats */ 1539 tx_lane_head = dlstat_tx_lane_stats(dh, linkid); 1540 if (tx_lane_head == NULL) 1541 goto done; 1542 1543 total_stats = calloc(1, sizeof (tx_lane_stat_entry_t)); 1544 if (total_stats == NULL) 1545 goto done; 1546 1547 total_stats->tle_index = DLSTAT_INVALID_ENTRY; 1548 total_stats->tle_id = DLSTAT_INVALID_ENTRY; 1549 1550 for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) { 1551 tx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 1552 1553 i_dlstat_sum_stats(&total_stats->tle_stats, 1554 &curr_lane_stats->tle_stats, &total_stats->tle_stats, 1555 tx_lane_stats_list, TX_LANE_STAT_SIZE); 1556 } 1557 1558 total_head = malloc(sizeof (dladm_stat_chain_t)); 1559 if (total_head == NULL) { 1560 free(total_stats); 1561 goto done; 1562 } 1563 1564 total_head->dc_statentry = total_stats; 1565 (void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total", 1566 sizeof (total_head->dc_statheader)); 1567 total_head->dc_next = NULL; 1568 free(tx_lane_head); 1569 1570 done: 1571 return (total_head); 1572 } 1573 1574 /* Fanout specific functions */ 1575 static boolean_t 1576 i_dlstat_fanout_match(void *arg1, void *arg2) 1577 { 1578 fanout_stat_entry_t *s1 = arg1; 1579 fanout_stat_entry_t *s2 = arg2; 1580 1581 return (s1->fe_index == s2->fe_index && 1582 s1->fe_id == s2->fe_id && 1583 s1->fe_foutindex == s2->fe_foutindex); 1584 } 1585 1586 static void * 1587 i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2) 1588 { 1589 fanout_stat_entry_t *s1 = arg1; 1590 fanout_stat_entry_t *s2 = arg2; 1591 fanout_stat_entry_t *diff_entry; 1592 1593 diff_entry = malloc(sizeof (fanout_stat_entry_t)); 1594 if (diff_entry == NULL) 1595 goto done; 1596 1597 diff_entry->fe_index = s1->fe_index; 1598 diff_entry->fe_id = s1->fe_id; 1599 diff_entry->fe_foutindex = s1->fe_foutindex; 1600 1601 DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list, 1602 FANOUT_STAT_SIZE); 1603 1604 done: 1605 return (diff_entry); 1606 } 1607 1608 static void * 1609 i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1610 { 1611 fanout_stat_entry_t *fanout_stat_entry; 1612 1613 fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t)); 1614 if (fanout_stat_entry == NULL) 1615 goto done; 1616 1617 /* Set by the caller later */ 1618 fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY; 1619 fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY; 1620 1621 fanout_stat_entry->fe_foutindex = i; 1622 1623 i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats, 1624 fanout_stats_list, FANOUT_STAT_SIZE); 1625 1626 done: 1627 return (fanout_stat_entry); 1628 } 1629 1630 static void * 1631 i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid, 1632 uint_t idlist[], uint_t idlist_size, 1633 const char *modname, const char *prefix) 1634 { 1635 int i; 1636 char statprefix[MAXLINKNAMELEN]; 1637 char linkname[MAXLINKNAMELEN]; 1638 dladm_stat_chain_t *curr, *curr_head; 1639 dladm_stat_chain_t *head = NULL, *prev = NULL; 1640 uint_t fanout_idlist[MAX_RINGS_PER_GROUP]; 1641 uint_t fanout_idlist_size; 1642 1643 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1644 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1645 return (NULL); 1646 } 1647 1648 i_dlstat_get_idlist(dh, linkname, DLSTAT_FANOUT_IDLIST, 1649 fanout_idlist, &fanout_idlist_size); 1650 1651 for (i = 0; i < idlist_size; i++) { 1652 uint_t index = idlist[i]; 1653 1654 (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout", 1655 prefix, index); 1656 1657 curr_head = i_dlstat_query_stats(dh, modname, statprefix, 1658 fanout_idlist, fanout_idlist_size, 1659 i_dlstat_fanout_retrieve_stat); 1660 1661 if (curr_head == NULL) /* Last lane */ 1662 break; 1663 1664 if (head == NULL) /* First lane */ 1665 head = curr_head; 1666 else /* Link new lane list to end of previous lane list */ 1667 prev->dc_next = curr_head; 1668 1669 /* Walk new lane list and set ids */ 1670 for (curr = curr_head; curr != NULL; curr = curr->dc_next) { 1671 fanout_stat_entry_t *curr_stats = curr->dc_statentry; 1672 1673 curr_stats->fe_index = index; 1674 curr_stats->fe_id = L_HWLANE; 1675 /* 1676 * Save last pointer of previous linked list. 1677 * This pointer is used to chain linked lists 1678 * generated in each iteration. 1679 */ 1680 prev = curr; 1681 } 1682 } 1683 1684 return (head); 1685 } 1686 1687 void * 1688 dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid, 1689 const char *linkname) 1690 { 1691 return (i_dlstat_query_fanout_stats(dh, linkid, 1692 default_idlist, default_idlist_size, linkname, 1693 DLSTAT_MAC_RX_SWLANE)); 1694 } 1695 1696 void * 1697 dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid, 1698 const char *linkname) 1699 { 1700 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1701 uint_t rx_hwlane_idlist_size; 1702 1703 i_dlstat_get_idlist(dh, linkname, DLSTAT_RX_HWLANE_IDLIST, 1704 rx_hwlane_idlist, &rx_hwlane_idlist_size); 1705 1706 return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist, 1707 rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE)); 1708 } 1709 1710 void * 1711 dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid) 1712 { 1713 dladm_stat_chain_t *head = NULL; 1714 dladm_stat_chain_t *fout_hwlane_stats; 1715 dladm_stat_chain_t *fout_swlane_and_local_stats; 1716 fanout_stat_entry_t *fout_stats; 1717 char linkname[MAXLINKNAMELEN]; 1718 1719 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1720 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1721 goto done; 1722 } 1723 1724 fout_swlane_and_local_stats = 1725 dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname); 1726 fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname); 1727 1728 if (fout_swlane_and_local_stats == NULL) { 1729 head = fout_hwlane_stats; 1730 goto done; 1731 } 1732 1733 fout_stats = fout_swlane_and_local_stats->dc_statentry; 1734 1735 if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */ 1736 fout_stats->fe_id = L_LOCAL; 1737 fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 1738 } else { /* no hwlane, mix of local+sw classified */ 1739 fout_stats->fe_id = L_LCLSWLANE; 1740 fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 1741 } 1742 1743 fout_swlane_and_local_stats->dc_next = fout_hwlane_stats; 1744 head = fout_swlane_and_local_stats; 1745 1746 done: 1747 return (head); 1748 } 1749 1750 /* Rx ring statistic specific functions */ 1751 static boolean_t 1752 i_dlstat_rx_ring_match(void *arg1, void *arg2) 1753 { 1754 rx_lane_stat_entry_t *s1 = arg1; 1755 rx_lane_stat_entry_t *s2 = arg2; 1756 1757 return (s1->rle_index == s2->rle_index); 1758 } 1759 1760 static void * 1761 i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2) 1762 { 1763 ring_stat_entry_t *s1 = arg1; 1764 ring_stat_entry_t *s2 = arg2; 1765 ring_stat_entry_t *diff_entry; 1766 1767 diff_entry = malloc(sizeof (ring_stat_entry_t)); 1768 if (diff_entry == NULL) 1769 goto done; 1770 1771 diff_entry->re_index = s1->re_index; 1772 1773 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list, 1774 RX_RING_STAT_SIZE); 1775 1776 done: 1777 return (diff_entry); 1778 } 1779 1780 static void * 1781 i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1782 { 1783 ring_stat_entry_t *rx_ring_stat_entry; 1784 1785 rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 1786 if (rx_ring_stat_entry == NULL) 1787 goto done; 1788 1789 rx_ring_stat_entry->re_index = i; 1790 1791 i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats, 1792 rx_ring_stats_list, RX_RING_STAT_SIZE); 1793 1794 done: 1795 return (rx_ring_stat_entry); 1796 } 1797 1798 void * 1799 dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 1800 { 1801 uint_t rx_ring_idlist[MAX_RINGS_PER_GROUP]; 1802 uint_t rx_ring_idlist_size; 1803 dladm_phys_attr_t dpa; 1804 char linkname[MAXLINKNAMELEN]; 1805 char *modname; 1806 datalink_class_t class; 1807 1808 /* 1809 * kstats corresponding to physical device rings continue to use 1810 * device names even if the link is renamed using dladm rename-link. 1811 * Thus, given a linkid, we lookup the physical device name. 1812 * However, if an aggr is renamed, kstats corresponding to its 1813 * pseudo rings are renamed as well. 1814 */ 1815 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 1816 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1817 return (NULL); 1818 } 1819 1820 if (class != DATALINK_CLASS_AGGR) { 1821 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 1822 DLADM_STATUS_OK) { 1823 return (NULL); 1824 } 1825 modname = dpa.dp_dev; 1826 } else 1827 modname = linkname; 1828 1829 i_dlstat_get_idlist(dh, modname, DLSTAT_RX_RING_IDLIST, 1830 rx_ring_idlist, &rx_ring_idlist_size); 1831 1832 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_RX_RING, 1833 rx_ring_idlist, rx_ring_idlist_size, 1834 i_dlstat_rx_ring_retrieve_stat)); 1835 } 1836 1837 /* Tx ring statistic specific functions */ 1838 static boolean_t 1839 i_dlstat_tx_ring_match(void *arg1, void *arg2) 1840 { 1841 tx_lane_stat_entry_t *s1 = arg1; 1842 tx_lane_stat_entry_t *s2 = arg2; 1843 1844 return (s1->tle_index == s2->tle_index); 1845 } 1846 1847 static void * 1848 i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2) 1849 { 1850 ring_stat_entry_t *s1 = arg1; 1851 ring_stat_entry_t *s2 = arg2; 1852 ring_stat_entry_t *diff_entry; 1853 1854 diff_entry = malloc(sizeof (ring_stat_entry_t)); 1855 if (diff_entry == NULL) 1856 goto done; 1857 1858 diff_entry->re_index = s1->re_index; 1859 1860 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list, 1861 TX_RING_STAT_SIZE); 1862 1863 done: 1864 return (diff_entry); 1865 } 1866 1867 static void * 1868 i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1869 { 1870 ring_stat_entry_t *tx_ring_stat_entry; 1871 1872 tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 1873 if (tx_ring_stat_entry == NULL) 1874 goto done; 1875 1876 tx_ring_stat_entry->re_index = i; 1877 1878 i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats, 1879 tx_ring_stats_list, TX_RING_STAT_SIZE); 1880 1881 done: 1882 return (tx_ring_stat_entry); 1883 } 1884 1885 void * 1886 dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 1887 { 1888 uint_t tx_ring_idlist[MAX_RINGS_PER_GROUP]; 1889 uint_t tx_ring_idlist_size; 1890 dladm_phys_attr_t dpa; 1891 char linkname[MAXLINKNAMELEN]; 1892 char *modname; 1893 datalink_class_t class; 1894 1895 /* 1896 * kstats corresponding to physical device rings continue to use 1897 * device names even if the link is renamed using dladm rename-link. 1898 * Thus, given a linkid, we lookup the physical device name. 1899 * However, if an aggr is renamed, kstats corresponding to its 1900 * pseudo rings are renamed as well. 1901 */ 1902 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 1903 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1904 return (NULL); 1905 } 1906 1907 if (class != DATALINK_CLASS_AGGR) { 1908 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 1909 DLADM_STATUS_OK) { 1910 return (NULL); 1911 } 1912 modname = dpa.dp_dev; 1913 } else 1914 modname = linkname; 1915 1916 i_dlstat_get_idlist(dh, modname, DLSTAT_TX_RING_IDLIST, 1917 tx_ring_idlist, &tx_ring_idlist_size); 1918 1919 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_TX_RING, 1920 tx_ring_idlist, tx_ring_idlist_size, 1921 i_dlstat_tx_ring_retrieve_stat)); 1922 } 1923 1924 /* Rx ring total statistic specific functions */ 1925 void * 1926 dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1927 { 1928 dladm_stat_chain_t *total_head = NULL; 1929 dladm_stat_chain_t *rx_ring_head, *curr; 1930 ring_stat_entry_t *total_stats; 1931 1932 /* Get per rx ring stats */ 1933 rx_ring_head = dlstat_rx_ring_stats(dh, linkid); 1934 if (rx_ring_head == NULL) 1935 goto done; 1936 1937 total_stats = calloc(1, sizeof (ring_stat_entry_t)); 1938 if (total_stats == NULL) 1939 goto done; 1940 1941 total_stats->re_index = DLSTAT_INVALID_ENTRY; 1942 1943 for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) { 1944 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 1945 1946 i_dlstat_sum_stats(&total_stats->re_stats, 1947 &curr_ring_stats->re_stats, &total_stats->re_stats, 1948 rx_ring_stats_list, RX_RING_STAT_SIZE); 1949 } 1950 1951 total_head = malloc(sizeof (dladm_stat_chain_t)); 1952 if (total_head == NULL) { 1953 free(total_stats); 1954 goto done; 1955 } 1956 1957 total_head->dc_statentry = total_stats; 1958 (void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total", 1959 sizeof (total_head->dc_statheader)); 1960 total_head->dc_next = NULL; 1961 free(rx_ring_head); 1962 1963 done: 1964 return (total_head); 1965 } 1966 1967 /* Tx ring total statistic specific functions */ 1968 void * 1969 dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1970 { 1971 dladm_stat_chain_t *total_head = NULL; 1972 dladm_stat_chain_t *tx_ring_head, *curr; 1973 ring_stat_entry_t *total_stats; 1974 1975 /* Get per tx ring stats */ 1976 tx_ring_head = dlstat_tx_ring_stats(dh, linkid); 1977 if (tx_ring_head == NULL) 1978 goto done; 1979 1980 total_stats = calloc(1, sizeof (ring_stat_entry_t)); 1981 if (total_stats == NULL) 1982 goto done; 1983 1984 total_stats->re_index = DLSTAT_INVALID_ENTRY; 1985 1986 for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) { 1987 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 1988 1989 i_dlstat_sum_stats(&total_stats->re_stats, 1990 &curr_ring_stats->re_stats, &total_stats->re_stats, 1991 tx_ring_stats_list, TX_RING_STAT_SIZE); 1992 } 1993 1994 total_head = malloc(sizeof (dladm_stat_chain_t)); 1995 if (total_head == NULL) { 1996 free(total_stats); 1997 goto done; 1998 } 1999 2000 total_head->dc_statentry = total_stats; 2001 (void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total", 2002 sizeof (total_head->dc_statheader)); 2003 total_head->dc_next = NULL; 2004 free(tx_ring_head); 2005 2006 done: 2007 return (total_head); 2008 } 2009 2010 /* Summary statistic specific functions */ 2011 static boolean_t 2012 i_dlstat_total_match(void *arg1 __unused, void *arg2 __unused) 2013 { 2014 /* Always single entry for total */ 2015 return (B_TRUE); 2016 } 2017 2018 static void * 2019 i_dlstat_total_stat_entry_diff(void *arg1, void *arg2) 2020 { 2021 total_stat_entry_t *s1 = arg1; 2022 total_stat_entry_t *s2 = arg2; 2023 total_stat_entry_t *diff_entry; 2024 2025 diff_entry = malloc(sizeof (total_stat_entry_t)); 2026 if (diff_entry == NULL) 2027 goto done; 2028 2029 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list, 2030 TOTAL_STAT_SIZE); 2031 2032 done: 2033 return (diff_entry); 2034 } 2035 2036 void * 2037 dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid) 2038 { 2039 dladm_stat_chain_t *head = NULL; 2040 dladm_stat_chain_t *rx_total; 2041 dladm_stat_chain_t *tx_total; 2042 total_stat_entry_t *total_stat_entry; 2043 rx_lane_stat_entry_t *rx_lane_stat_entry; 2044 tx_lane_stat_entry_t *tx_lane_stat_entry; 2045 2046 /* Get total rx lane stats */ 2047 rx_total = dlstat_rx_lane_total_stats(dh, linkid); 2048 if (rx_total == NULL) 2049 goto done; 2050 2051 /* Get total tx lane stats */ 2052 tx_total = dlstat_tx_lane_total_stats(dh, linkid); 2053 if (tx_total == NULL) 2054 goto done; 2055 2056 /* Build total stat */ 2057 total_stat_entry = calloc(1, sizeof (total_stat_entry_t)); 2058 if (total_stat_entry == NULL) 2059 goto done; 2060 2061 rx_lane_stat_entry = rx_total->dc_statentry; 2062 tx_lane_stat_entry = tx_total->dc_statentry; 2063 2064 /* Extract total rx ipackets, rbytes */ 2065 total_stat_entry->tse_stats.ts_ipackets = 2066 rx_lane_stat_entry->rle_stats.rl_ipackets; 2067 total_stat_entry->tse_stats.ts_rbytes = 2068 rx_lane_stat_entry->rle_stats.rl_rbytes; 2069 2070 /* Extract total tx opackets, obytes */ 2071 total_stat_entry->tse_stats.ts_opackets = 2072 tx_lane_stat_entry->tle_stats.tl_opackets; 2073 total_stat_entry->tse_stats.ts_obytes = 2074 tx_lane_stat_entry->tle_stats.tl_obytes; 2075 2076 head = malloc(sizeof (dladm_stat_chain_t)); 2077 if (head == NULL) { 2078 free(total_stat_entry); 2079 goto done; 2080 } 2081 2082 head->dc_statentry = total_stat_entry; 2083 (void) strlcpy(head->dc_statheader, "mac_lane_total", 2084 sizeof (head->dc_statheader)); 2085 head->dc_next = NULL; 2086 free(rx_total); 2087 free(tx_total); 2088 2089 done: 2090 return (head); 2091 } 2092 2093 /* Aggr total statistic(summed across all component ports) specific functions */ 2094 void * 2095 dlstat_aggr_total_stats(dladm_stat_chain_t *head) 2096 { 2097 dladm_stat_chain_t *curr; 2098 dladm_stat_chain_t *total_head = NULL; 2099 aggr_port_stat_entry_t *total_stats; 2100 2101 total_stats = calloc(1, sizeof (aggr_port_stat_entry_t)); 2102 if (total_stats == NULL) 2103 goto done; 2104 2105 total_stats->ape_portlinkid = DATALINK_INVALID_LINKID; 2106 2107 for (curr = head; curr != NULL; curr = curr->dc_next) { 2108 aggr_port_stat_entry_t *curr_aggr_port_stats; 2109 2110 curr_aggr_port_stats = curr->dc_statentry; 2111 2112 i_dlstat_sum_stats(&total_stats->ape_stats, 2113 &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats, 2114 aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 2115 } 2116 2117 total_head = malloc(sizeof (dladm_stat_chain_t)); 2118 if (total_head == NULL) { 2119 free(total_stats); 2120 goto done; 2121 } 2122 2123 total_head->dc_statentry = total_stats; 2124 total_head->dc_next = NULL; 2125 2126 done: 2127 return (total_head); 2128 } 2129 2130 /* Aggr port statistic specific functions */ 2131 static boolean_t 2132 i_dlstat_aggr_port_match(void *arg1, void *arg2) 2133 { 2134 aggr_port_stat_entry_t *s1 = arg1; 2135 aggr_port_stat_entry_t *s2 = arg2; 2136 2137 return (s1->ape_portlinkid == s2->ape_portlinkid); 2138 } 2139 2140 static void * 2141 i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2) 2142 { 2143 aggr_port_stat_entry_t *s1 = arg1; 2144 aggr_port_stat_entry_t *s2 = arg2; 2145 aggr_port_stat_entry_t *diff_entry; 2146 2147 diff_entry = malloc(sizeof (aggr_port_stat_entry_t)); 2148 if (diff_entry == NULL) 2149 goto done; 2150 2151 diff_entry->ape_portlinkid = s1->ape_portlinkid; 2152 2153 DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list, 2154 AGGR_PORT_STAT_SIZE); 2155 2156 done: 2157 return (diff_entry); 2158 } 2159 2160 /* 2161 * Query dls stats for the aggr port. This results in query for stats into 2162 * the corresponding device driver. 2163 */ 2164 static aggr_port_stat_entry_t * 2165 i_dlstat_single_port_stats(dladm_handle_t handle, const char *portname, 2166 datalink_id_t linkid) 2167 { 2168 kstat_t *ksp; 2169 char module[DLPI_LINKNAME_MAX]; 2170 uint_t instance; 2171 aggr_port_stat_entry_t *aggr_port_stat_entry = NULL; 2172 2173 if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK) 2174 goto done; 2175 2176 if (dladm_dld_kcp(handle) == NULL) { 2177 warn("kstat open operation failed"); 2178 return (NULL); 2179 } 2180 2181 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), module, instance, 2182 "mac", NULL); 2183 if (ksp == NULL) 2184 goto done; 2185 2186 aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t)); 2187 if (aggr_port_stat_entry == NULL) 2188 goto done; 2189 2190 /* Save port's linkid */ 2191 aggr_port_stat_entry->ape_portlinkid = linkid; 2192 2193 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, 2194 &aggr_port_stat_entry->ape_stats, 2195 aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 2196 done: 2197 return (aggr_port_stat_entry); 2198 } 2199 2200 void * 2201 dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid) 2202 { 2203 dladm_aggr_grp_attr_t ginfo; 2204 int i; 2205 dladm_aggr_port_attr_t *portp; 2206 dladm_phys_attr_t dpa; 2207 aggr_port_stat_entry_t *aggr_port_stat_entry; 2208 dladm_stat_chain_t *head = NULL, *prev = NULL, *curr; 2209 dladm_stat_chain_t *total_stats; 2210 2211 /* Get aggr info */ 2212 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2213 if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE) 2214 != DLADM_STATUS_OK) 2215 goto done; 2216 /* For every port that is member of this aggr do */ 2217 for (i = 0; i < ginfo.lg_nports; i++) { 2218 portp = &(ginfo.lg_ports[i]); 2219 if (dladm_phys_info(dh, portp->lp_linkid, &dpa, 2220 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { 2221 goto done; 2222 } 2223 2224 aggr_port_stat_entry = i_dlstat_single_port_stats(dh, 2225 dpa.dp_dev, portp->lp_linkid); 2226 2227 /* Create dladm_stat_chain_t object for this stat */ 2228 curr = malloc(sizeof (dladm_stat_chain_t)); 2229 if (curr == NULL) { 2230 free(aggr_port_stat_entry); 2231 goto done; 2232 } 2233 (void) strlcpy(curr->dc_statheader, dpa.dp_dev, 2234 sizeof (curr->dc_statheader)); 2235 curr->dc_statentry = aggr_port_stat_entry; 2236 curr->dc_next = NULL; 2237 2238 /* Chain this aggr port stat entry */ 2239 /* head of the stat list */ 2240 if (prev == NULL) 2241 head = curr; 2242 else 2243 prev->dc_next = curr; 2244 prev = curr; 2245 } 2246 2247 /* 2248 * Prepend the stat list with cumulative aggr stats i.e. summed over all 2249 * component ports 2250 */ 2251 total_stats = dlstat_aggr_total_stats(head); 2252 if (total_stats != NULL) { 2253 total_stats->dc_next = head; 2254 head = total_stats; 2255 } 2256 2257 done: 2258 free(ginfo.lg_ports); 2259 return (head); 2260 } 2261 2262 /* Misc stat specific functions */ 2263 void * 2264 dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid) 2265 { 2266 misc_stat_entry_t *misc_stat_entry; 2267 dladm_stat_chain_t *head = NULL; 2268 char linkname[MAXLINKNAMELEN]; 2269 2270 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 2271 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2272 goto done; 2273 } 2274 2275 misc_stat_entry = i_dlstat_misc_stats(dh, linkname); 2276 if (misc_stat_entry == NULL) 2277 goto done; 2278 2279 head = malloc(sizeof (dladm_stat_chain_t)); 2280 if (head == NULL) { 2281 free(misc_stat_entry); 2282 goto done; 2283 } 2284 2285 head->dc_statentry = misc_stat_entry; 2286 (void) strlcpy(head->dc_statheader, "mac_misc_stat", 2287 sizeof (head->dc_statheader)); 2288 head->dc_next = NULL; 2289 2290 done: 2291 return (head); 2292 } 2293 2294 /* Exported functions */ 2295 dladm_stat_chain_t * 2296 dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid, 2297 dladm_stat_type_t stattype) 2298 { 2299 return (dladm_stat_table[stattype].ds_querystat(dh, linkid)); 2300 } 2301 2302 dladm_stat_chain_t * 2303 dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2, 2304 dladm_stat_type_t stattype) 2305 { 2306 dladm_stat_chain_t *op1_curr, *op2_curr; 2307 dladm_stat_chain_t *diff_curr; 2308 dladm_stat_chain_t *diff_prev = NULL, *diff_head = NULL; 2309 2310 /* Perform op1 - op2, store result in diff */ 2311 for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) { 2312 for (op2_curr = op2; op2_curr != NULL; 2313 op2_curr = op2_curr->dc_next) { 2314 if (dlstat_match_stats(op1_curr->dc_statentry, 2315 op2_curr->dc_statentry, stattype)) { 2316 break; 2317 } 2318 } 2319 diff_curr = malloc(sizeof (dladm_stat_chain_t)); 2320 if (diff_curr == NULL) 2321 goto done; 2322 2323 diff_curr->dc_next = NULL; 2324 2325 if (op2_curr == NULL) { 2326 /* prev iteration did not have this stat entry */ 2327 diff_curr->dc_statentry = 2328 dlstat_diff_stats(op1_curr->dc_statentry, 2329 NULL, stattype); 2330 } else { 2331 diff_curr->dc_statentry = 2332 dlstat_diff_stats(op1_curr->dc_statentry, 2333 op2_curr->dc_statentry, stattype); 2334 } 2335 2336 if (diff_curr->dc_statentry == NULL) { 2337 free(diff_curr); 2338 goto done; 2339 } 2340 2341 if (diff_prev == NULL) /* head of the diff stat list */ 2342 diff_head = diff_curr; 2343 else 2344 diff_prev->dc_next = diff_curr; 2345 diff_prev = diff_curr; 2346 } 2347 done: 2348 return (diff_head); 2349 } 2350 2351 void 2352 dladm_link_stat_free(dladm_stat_chain_t *curr) 2353 { 2354 while (curr != NULL) { 2355 dladm_stat_chain_t *tofree = curr; 2356 2357 curr = curr->dc_next; 2358 free(tofree->dc_statentry); 2359 free(tofree); 2360 } 2361 } 2362 2363 /* Query all link stats */ 2364 static name_value_stat_t * 2365 i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size) 2366 { 2367 int i; 2368 name_value_stat_t *head_stat = NULL, *prev_stat = NULL; 2369 name_value_stat_t *curr_stat; 2370 2371 for (i = 0; i < size; i++) { 2372 uint64_t *val = (void *) 2373 ((uchar_t *)stats + stats_list[i].si_offset); 2374 2375 curr_stat = calloc(1, sizeof (name_value_stat_t)); 2376 if (curr_stat == NULL) 2377 break; 2378 2379 (void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name, 2380 sizeof (curr_stat->nv_statname)); 2381 curr_stat->nv_statval = *val; 2382 curr_stat->nv_nextstat = NULL; 2383 2384 if (head_stat == NULL) /* First node */ 2385 head_stat = curr_stat; 2386 else 2387 prev_stat->nv_nextstat = curr_stat; 2388 2389 prev_stat = curr_stat; 2390 } 2391 return (head_stat); 2392 } 2393 2394 void * 2395 build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype) 2396 { 2397 name_value_stat_entry_t *name_value_stat_entry; 2398 dladm_stat_desc_t *stattbl_ptr; 2399 void *statfields; 2400 2401 stattbl_ptr = &dladm_stat_table[stattype]; 2402 2403 /* Allocate memory for query all stat entry */ 2404 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 2405 if (name_value_stat_entry == NULL) 2406 goto done; 2407 2408 /* Header for these stat fields */ 2409 (void) strlcpy(name_value_stat_entry->nve_header, statheader, 2410 sizeof (name_value_stat_entry->nve_header)); 2411 2412 /* Extract stat fields from the statentry */ 2413 statfields = (uchar_t *)statentry + 2414 dladm_stat_table[stattype].ds_offset; 2415 2416 /* Convert curr_stat to <statname, statval> pair */ 2417 name_value_stat_entry->nve_stats = 2418 i_dlstat_convert_stats(statfields, 2419 stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize); 2420 done: 2421 return (name_value_stat_entry); 2422 } 2423 2424 void * 2425 i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype) 2426 { 2427 dladm_stat_chain_t *curr; 2428 dladm_stat_chain_t *nvstat_head = NULL, *nvstat_prev = NULL; 2429 dladm_stat_chain_t *nvstat_curr; 2430 2431 /* 2432 * For every stat in the chain, build header and convert all 2433 * its stat fields 2434 */ 2435 for (curr = stat_head; curr != NULL; curr = curr->dc_next) { 2436 nvstat_curr = malloc(sizeof (dladm_stat_chain_t)); 2437 if (nvstat_curr == NULL) 2438 break; 2439 2440 nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader, 2441 curr->dc_statentry, stattype); 2442 2443 if (nvstat_curr->dc_statentry == NULL) { 2444 free(nvstat_curr); 2445 break; 2446 } 2447 2448 nvstat_curr->dc_next = NULL; 2449 2450 if (nvstat_head == NULL) /* First node */ 2451 nvstat_head = nvstat_curr; 2452 else 2453 nvstat_prev->dc_next = nvstat_curr; 2454 2455 nvstat_prev = nvstat_curr; 2456 } 2457 return (nvstat_head); 2458 } 2459 2460 dladm_stat_chain_t * 2461 dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid, 2462 dladm_stat_type_t stattype) 2463 { 2464 dladm_stat_chain_t *stat_head; 2465 dladm_stat_chain_t *nvstat_head = NULL; 2466 2467 /* Query the requested stat */ 2468 stat_head = dladm_link_stat_query(dh, linkid, stattype); 2469 if (stat_head == NULL) 2470 goto done; 2471 2472 /* 2473 * Convert every statfield in every stat-entry of stat chain to 2474 * <statname, statval> pair 2475 */ 2476 nvstat_head = i_walk_dlstat_chain(stat_head, stattype); 2477 2478 /* Free stat_head */ 2479 dladm_link_stat_free(stat_head); 2480 2481 done: 2482 return (nvstat_head); 2483 } 2484 2485 void 2486 dladm_link_stat_query_all_free(dladm_stat_chain_t *curr) 2487 { 2488 while (curr != NULL) { 2489 dladm_stat_chain_t *tofree = curr; 2490 name_value_stat_entry_t *nv_entry = curr->dc_statentry; 2491 name_value_stat_t *nv_curr = nv_entry->nve_stats; 2492 2493 while (nv_curr != NULL) { 2494 name_value_stat_t *nv_tofree = nv_curr; 2495 2496 nv_curr = nv_curr->nv_nextstat; 2497 free(nv_tofree); 2498 } 2499 2500 curr = curr->dc_next; 2501 free(nv_entry); 2502 free(tofree); 2503 } 2504 } 2505 2506 /* flow stats specific routines */ 2507 flow_stat_t * 2508 dladm_flow_stat_query(dladm_handle_t handle, const char *flowname) 2509 { 2510 kstat_t *ksp; 2511 flow_stat_t *flow_stat = NULL; 2512 2513 if (dladm_dld_kcp(handle) == NULL) 2514 return (NULL); 2515 2516 flow_stat = calloc(1, sizeof (flow_stat_t)); 2517 if (flow_stat == NULL) 2518 goto done; 2519 2520 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), NULL, -1, flowname, 2521 "flow"); 2522 2523 if (ksp != NULL) { 2524 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, flow_stat, 2525 flow_stats_list, FLOW_STAT_SIZE); 2526 } 2527 2528 done: 2529 return (flow_stat); 2530 } 2531 2532 flow_stat_t * 2533 dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2) 2534 { 2535 flow_stat_t *diff_stat; 2536 2537 diff_stat = calloc(1, sizeof (flow_stat_t)); 2538 if (diff_stat == NULL) 2539 goto done; 2540 2541 if (op2 == NULL) { 2542 bcopy(op1, diff_stat, sizeof (flow_stat_t)); 2543 } else { 2544 i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list, 2545 FLOW_STAT_SIZE); 2546 } 2547 done: 2548 return (diff_stat); 2549 } 2550 2551 void 2552 dladm_flow_stat_free(flow_stat_t *curr) 2553 { 2554 free(curr); 2555 } 2556 2557 /* Query all flow stats */ 2558 name_value_stat_entry_t * 2559 dladm_flow_stat_query_all(dladm_handle_t handle, const char *flowname) 2560 { 2561 flow_stat_t *flow_stat; 2562 name_value_stat_entry_t *name_value_stat_entry = NULL; 2563 2564 /* Query flow stats */ 2565 flow_stat = dladm_flow_stat_query(handle, flowname); 2566 if (flow_stat == NULL) 2567 goto done; 2568 2569 /* Allocate memory for query all stat entry */ 2570 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 2571 if (name_value_stat_entry == NULL) { 2572 dladm_flow_stat_free(flow_stat); 2573 goto done; 2574 } 2575 2576 /* Header for these stat fields */ 2577 (void) strncpy(name_value_stat_entry->nve_header, flowname, 2578 MAXFLOWNAMELEN); 2579 2580 /* Convert every statfield in flow_stat to <statname, statval> pair */ 2581 name_value_stat_entry->nve_stats = 2582 i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE); 2583 2584 /* Free flow_stat */ 2585 dladm_flow_stat_free(flow_stat); 2586 2587 done: 2588 return (name_value_stat_entry); 2589 } 2590 2591 void 2592 dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr) 2593 { 2594 name_value_stat_t *nv_curr = curr->nve_stats; 2595 2596 while (nv_curr != NULL) { 2597 name_value_stat_t *nv_tofree = nv_curr; 2598 2599 nv_curr = nv_curr->nv_nextstat; 2600 free(nv_tofree); 2601 } 2602 } 2603