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