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 if (kstat_read(dladm_dld_kcp(handle), ksp, NULL) == -1) 217 goto bail; 218 219 if (dladm_kstat_value(ksp, name, type, val) < 0) 220 goto bail; 221 222 return (DLADM_STATUS_OK); 223 224 bail: 225 return (dladm_errno2status(errno)); 226 } 227 228 /* Compute sum of 2 pktsums (s1 = s2 + s3) */ 229 void 230 dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 231 { 232 s1->rbytes = s2->rbytes + s3->rbytes; 233 s1->ipackets = s2->ipackets + s3->ipackets; 234 s1->ierrors = s2->ierrors + s3->ierrors; 235 s1->obytes = s2->obytes + s3->obytes; 236 s1->opackets = s2->opackets + s3->opackets; 237 s1->oerrors = s2->oerrors + s3->oerrors; 238 s1->snaptime = s2->snaptime; 239 } 240 241 #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0) 242 243 244 /* Compute differences between 2 pktsums (s1 = s2 - s3) */ 245 void 246 dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 247 { 248 s1->rbytes = DIFF_STAT(s2->rbytes, s3->rbytes); 249 s1->ipackets = DIFF_STAT(s2->ipackets, s3->ipackets); 250 s1->ierrors = DIFF_STAT(s2->ierrors, s3->ierrors); 251 s1->obytes = DIFF_STAT(s2->obytes, s3->obytes); 252 s1->opackets = DIFF_STAT(s2->opackets, s3->opackets); 253 s1->oerrors = DIFF_STAT(s2->oerrors, s3->oerrors); 254 s1->snaptime = DIFF_STAT(s2->snaptime, s3->snaptime); 255 } 256 257 #define DLSTAT_MAC_RX_SWLANE "mac_rx_swlane" 258 #define DLSTAT_MAC_RX_HWLANE "mac_rx_hwlane" 259 #define DLSTAT_MAC_TX_SWLANE "mac_tx_swlane" 260 #define DLSTAT_MAC_TX_HWLANE "mac_tx_hwlane" 261 #define DLSTAT_MAC_MISC_STAT "mac_misc_stat" 262 #define DLSTAT_MAC_RX_RING "mac_rx_ring" 263 #define DLSTAT_MAC_TX_RING "mac_tx_ring" 264 #define DLSTAT_MAC_FANOUT "mac_rx_swlane0_fanout" 265 266 typedef struct { 267 const char *si_name; 268 uint_t si_offset; 269 } stat_info_t; 270 271 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0])) 272 273 /* Definitions for rx lane stats */ 274 #define RL_OFF(f) (offsetof(rx_lane_stat_t, f)) 275 276 static stat_info_t rx_hwlane_stats_list[] = { 277 {"ipackets", RL_OFF(rl_ipackets)}, 278 {"rbytes", RL_OFF(rl_rbytes)}, 279 {"intrs", RL_OFF(rl_intrs)}, 280 {"intrbytes", RL_OFF(rl_intrbytes)}, 281 {"polls", RL_OFF(rl_polls)}, 282 {"pollbytes", RL_OFF(rl_pollbytes)}, 283 {"rxsdrops", RL_OFF(rl_sdrops)}, 284 {"chainunder10", RL_OFF(rl_chl10)}, 285 {"chain10to50", RL_OFF(rl_ch10_50)}, 286 {"chainover50", RL_OFF(rl_chg50)} 287 }; 288 #define RX_HWLANE_STAT_SIZE A_CNT(rx_hwlane_stats_list) 289 290 static stat_info_t rx_swlane_stats_list[] = { 291 {"ipackets", RL_OFF(rl_ipackets)}, 292 {"rbytes", RL_OFF(rl_rbytes)}, 293 {"local", RL_OFF(rl_lclpackets)}, 294 {"localbytes", RL_OFF(rl_lclbytes)}, 295 {"intrs", RL_OFF(rl_intrs)}, 296 {"intrbytes", RL_OFF(rl_intrbytes)}, 297 {"rxsdrops", RL_OFF(rl_sdrops)} 298 }; 299 #define RX_SWLANE_STAT_SIZE A_CNT(rx_swlane_stats_list) 300 301 static stat_info_t rx_lane_stats_list[] = { 302 {"ipackets", RL_OFF(rl_ipackets)}, 303 {"rbytes", RL_OFF(rl_rbytes)}, 304 {"local", RL_OFF(rl_lclpackets)}, 305 {"localbytes", RL_OFF(rl_lclbytes)}, 306 {"intrs", RL_OFF(rl_intrs)}, 307 {"intrbytes", RL_OFF(rl_intrbytes)}, 308 {"polls", RL_OFF(rl_polls)}, 309 {"rxsdrops", RL_OFF(rl_sdrops)}, 310 {"pollbytes", RL_OFF(rl_pollbytes)}, 311 {"chainunder10", RL_OFF(rl_chl10)}, 312 {"chain10to50", RL_OFF(rl_ch10_50)}, 313 {"chainover50", RL_OFF(rl_chg50)} 314 }; 315 #define RX_LANE_STAT_SIZE A_CNT(rx_lane_stats_list) 316 317 /* Definitions for tx lane stats */ 318 #define TL_OFF(f) (offsetof(tx_lane_stat_t, f)) 319 320 static stat_info_t tx_lane_stats_list[] = { 321 {"opackets", TL_OFF(tl_opackets)}, 322 {"obytes", TL_OFF(tl_obytes)}, 323 {"blockcnt", TL_OFF(tl_blockcnt)}, 324 {"unblockcnt", TL_OFF(tl_unblockcnt)}, 325 {"txsdrops", TL_OFF(tl_sdrops)} 326 }; 327 #define TX_LANE_STAT_SIZE A_CNT(tx_lane_stats_list) 328 329 /* Definitions for tx/rx misc stats */ 330 #define M_OFF(f) (offsetof(misc_stat_t, f)) 331 332 static stat_info_t misc_stats_list[] = { 333 {"multircv", M_OFF(ms_multircv)}, 334 {"brdcstrcv", M_OFF(ms_brdcstrcv)}, 335 {"multixmt", M_OFF(ms_multixmt)}, 336 {"brdcstxmt", M_OFF(ms_brdcstxmt)}, 337 {"multircvbytes", M_OFF(ms_multircvbytes)}, 338 {"brdcstrcvbytes", M_OFF(ms_brdcstrcvbytes)}, 339 {"multixmtbytes", M_OFF(ms_multixmtbytes)}, 340 {"brdcstxmtbytes", M_OFF(ms_brdcstxmtbytes)}, 341 {"txerrors", M_OFF(ms_txerrors)}, 342 {"macspoofed", M_OFF(ms_macspoofed)}, 343 {"ipspoofed", M_OFF(ms_ipspoofed)}, 344 {"dhcpspoofed", M_OFF(ms_dhcpspoofed)}, 345 {"restricted", M_OFF(ms_restricted)}, 346 {"ipackets", M_OFF(ms_ipackets)}, 347 {"rbytes", M_OFF(ms_rbytes)}, 348 {"local", M_OFF(ms_local)}, 349 {"localbytes", M_OFF(ms_localbytes)}, 350 {"intrs", M_OFF(ms_intrs)}, 351 {"intrbytes", M_OFF(ms_intrbytes)}, 352 {"polls", M_OFF(ms_polls)}, 353 {"pollbytes", M_OFF(ms_pollbytes)}, 354 {"rxsdrops", M_OFF(ms_rxsdrops)}, 355 {"chainunder10", M_OFF(ms_chainunder10)}, 356 {"chain10to50", M_OFF(ms_chain10to50)}, 357 {"chainover50", M_OFF(ms_chainover50)}, 358 {"obytes", M_OFF(ms_obytes)}, 359 {"opackets", M_OFF(ms_opackets)}, 360 {"blockcnt", M_OFF(ms_blockcnt)}, 361 {"unblockcnt", M_OFF(ms_unblockcnt)}, 362 {"txsdrops", M_OFF(ms_txsdrops)} 363 }; 364 #define MISC_STAT_SIZE A_CNT(misc_stats_list) 365 366 /* Definitions for rx ring stats */ 367 #define R_OFF(f) (offsetof(ring_stat_t, f)) 368 369 static stat_info_t rx_ring_stats_list[] = { 370 {"ipackets", R_OFF(r_packets)}, 371 {"rbytes", R_OFF(r_bytes)} 372 }; 373 #define RX_RING_STAT_SIZE A_CNT(rx_ring_stats_list) 374 375 /* Definitions for tx ring stats */ 376 static stat_info_t tx_ring_stats_list[] = { 377 {"opackets", R_OFF(r_packets)}, 378 {"obytes", R_OFF(r_bytes)} 379 }; 380 #define TX_RING_STAT_SIZE A_CNT(tx_ring_stats_list) 381 382 /* Definitions for fanout stats */ 383 #define F_OFF(f) (offsetof(fanout_stat_t, f)) 384 385 static stat_info_t fanout_stats_list[] = { 386 {"ipackets", F_OFF(f_ipackets)}, 387 {"rbytes", F_OFF(f_rbytes)}, 388 }; 389 #define FANOUT_STAT_SIZE A_CNT(fanout_stats_list) 390 391 /* Definitions for total stats */ 392 #define T_OFF(f) (offsetof(total_stat_t, f)) 393 394 static stat_info_t total_stats_list[] = { 395 {"ipackets", T_OFF(ts_ipackets)}, 396 {"rbytes", T_OFF(ts_rbytes)}, 397 {"opackets", T_OFF(ts_opackets)}, 398 {"obytes", T_OFF(ts_obytes)} 399 }; 400 #define TOTAL_STAT_SIZE A_CNT(total_stats_list) 401 402 /* Definitions for aggr stats */ 403 #define AP_OFF(f) (offsetof(aggr_port_stat_t, f)) 404 405 static stat_info_t aggr_port_stats_list[] = { 406 {"ipackets64", AP_OFF(ap_ipackets)}, 407 {"rbytes64", AP_OFF(ap_rbytes)}, 408 {"opackets64", AP_OFF(ap_opackets)}, 409 {"obytes64", AP_OFF(ap_obytes)} 410 }; 411 #define AGGR_PORT_STAT_SIZE A_CNT(aggr_port_stats_list) 412 413 /* Definitions for flow stats */ 414 #define FL_OFF(f) (offsetof(flow_stat_t, f)) 415 416 static stat_info_t flow_stats_list[] = { 417 {"ipackets", FL_OFF(fl_ipackets)}, 418 {"rbytes", FL_OFF(fl_rbytes)}, 419 {"opackets", FL_OFF(fl_opackets)}, 420 {"obytes", FL_OFF(fl_obytes)} 421 }; 422 #define FLOW_STAT_SIZE A_CNT(flow_stats_list) 423 424 /* Rx lane specific functions */ 425 void * dlstat_rx_lane_stats(dladm_handle_t, datalink_id_t); 426 static boolean_t i_dlstat_rx_lane_match(void *, void *); 427 static void * i_dlstat_rx_lane_stat_entry_diff(void *, void *); 428 429 /* Tx lane specific functions */ 430 void * dlstat_tx_lane_stats(dladm_handle_t, datalink_id_t); 431 static boolean_t i_dlstat_tx_lane_match(void *, void *); 432 static void * i_dlstat_tx_lane_stat_entry_diff(void *, void *); 433 434 /* Rx lane total specific functions */ 435 void * dlstat_rx_lane_total_stats(dladm_handle_t, 436 datalink_id_t); 437 438 /* Tx lane total specific functions */ 439 void * dlstat_tx_lane_total_stats(dladm_handle_t, 440 datalink_id_t); 441 442 /* Fanout specific functions */ 443 void * dlstat_fanout_stats(dladm_handle_t, datalink_id_t); 444 static boolean_t i_dlstat_fanout_match(void *, void *); 445 static void * i_dlstat_fanout_stat_entry_diff(void *, void *); 446 447 /* Rx ring specific functions */ 448 void * dlstat_rx_ring_stats(dladm_handle_t, datalink_id_t); 449 static boolean_t i_dlstat_rx_ring_match(void *, void *); 450 static void * i_dlstat_rx_ring_stat_entry_diff(void *, void *); 451 452 /* Tx ring specific functions */ 453 void * dlstat_tx_ring_stats(dladm_handle_t, datalink_id_t); 454 static boolean_t i_dlstat_tx_ring_match(void *, void *); 455 static void * i_dlstat_tx_ring_stat_entry_diff(void *, void *); 456 457 /* Rx ring total specific functions */ 458 void * dlstat_rx_ring_total_stats(dladm_handle_t, 459 datalink_id_t); 460 461 /* Tx ring total specific functions */ 462 void * dlstat_tx_ring_total_stats(dladm_handle_t, 463 datalink_id_t); 464 465 /* Summary specific functions */ 466 void * dlstat_total_stats(dladm_handle_t, datalink_id_t); 467 static boolean_t i_dlstat_total_match(void *, void *); 468 static void * i_dlstat_total_stat_entry_diff(void *, void *); 469 470 /* Aggr port specific functions */ 471 void * dlstat_aggr_port_stats(dladm_handle_t, datalink_id_t); 472 static boolean_t i_dlstat_aggr_port_match(void *, void *); 473 static void * i_dlstat_aggr_port_stat_entry_diff(void *, void *); 474 475 /* Misc stat specific functions */ 476 void * dlstat_misc_stats(dladm_handle_t, datalink_id_t); 477 478 typedef void * dladm_stat_query_t(dladm_handle_t, datalink_id_t); 479 typedef boolean_t dladm_stat_match_t(void *, void *); 480 typedef void * dladm_stat_diff_t(void *, void *); 481 482 typedef struct dladm_stat_desc_s { 483 dladm_stat_type_t ds_stattype; 484 dladm_stat_query_t *ds_querystat; 485 dladm_stat_match_t *ds_matchstat; 486 dladm_stat_diff_t *ds_diffstat; 487 uint_t ds_offset; 488 stat_info_t *ds_statlist; 489 uint_t ds_statsize; 490 } dladm_stat_desc_t; 491 492 /* 493 * dladm_stat_table has one entry for each supported stat. ds_querystat returns 494 * a chain of 'stat entries' for the queried stat. 495 * Each stat entry has set of identifiers (ids) and an object containing actual 496 * stat values. These stat entry objects are chained together in a linked list 497 * of datatype dladm_stat_chain_t. Head of this list is returned to the caller 498 * of dladm_link_stat_query. 499 * 500 * One node in the chain is shown below: 501 * 502 * ------------------------- 503 * | dc_statentry | 504 * | -------------- | 505 * | | ids | | 506 * | -------------- | 507 * | | stat fields | | 508 * | -------------- | 509 * ------------------------- 510 * | dc_next ---------|------> to next stat entry 511 * ------------------------- 512 * 513 * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to 514 * object of type rx_lane_stat_entry_t. 515 * 516 * dladm_link_stat_query_all returns similar chain. However, instead of storing 517 * stat fields as raw numbers, it stores those as chain of <name, value> pairs. 518 * The resulting structure is depicted below: 519 * 520 * ------------------------- 521 * | dc_statentry | 522 * | -------------- | --------------- 523 * | | nv_header | | | name, val | 524 * | -------------- | --------------- 525 * | | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair 526 * | -------------- | --------------- 527 * ------------------------- 528 * | dc_next ---------|------> to next stat entry 529 * ------------------------- 530 */ 531 static dladm_stat_desc_t dladm_stat_table[] = { 532 { DLADM_STAT_RX_LANE, dlstat_rx_lane_stats, 533 i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff, 534 offsetof(rx_lane_stat_entry_t, rle_stats), 535 rx_lane_stats_list, RX_LANE_STAT_SIZE}, 536 537 { DLADM_STAT_TX_LANE, dlstat_tx_lane_stats, 538 i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff, 539 offsetof(tx_lane_stat_entry_t, tle_stats), 540 tx_lane_stats_list, TX_LANE_STAT_SIZE}, 541 542 { DLADM_STAT_RX_LANE_TOTAL, dlstat_rx_lane_total_stats, 543 i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff, 544 offsetof(rx_lane_stat_entry_t, rle_stats), 545 rx_lane_stats_list, RX_LANE_STAT_SIZE}, 546 547 { DLADM_STAT_TX_LANE_TOTAL, dlstat_tx_lane_total_stats, 548 i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff, 549 offsetof(tx_lane_stat_entry_t, tle_stats), 550 tx_lane_stats_list, TX_LANE_STAT_SIZE}, 551 552 { DLADM_STAT_RX_LANE_FOUT, dlstat_fanout_stats, 553 i_dlstat_fanout_match, i_dlstat_fanout_stat_entry_diff, 554 offsetof(fanout_stat_entry_t, fe_stats), 555 fanout_stats_list, FANOUT_STAT_SIZE}, 556 557 { DLADM_STAT_RX_RING, dlstat_rx_ring_stats, 558 i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff, 559 offsetof(ring_stat_entry_t, re_stats), 560 rx_ring_stats_list, RX_RING_STAT_SIZE}, 561 562 { DLADM_STAT_TX_RING, dlstat_tx_ring_stats, 563 i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff, 564 offsetof(ring_stat_entry_t, re_stats), 565 tx_ring_stats_list, TX_RING_STAT_SIZE}, 566 567 { DLADM_STAT_RX_RING_TOTAL, dlstat_rx_ring_total_stats, 568 i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff, 569 offsetof(ring_stat_entry_t, re_stats), 570 rx_ring_stats_list, RX_RING_STAT_SIZE}, 571 572 { DLADM_STAT_TX_RING_TOTAL, dlstat_tx_ring_total_stats, 573 i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff, 574 offsetof(ring_stat_entry_t, re_stats), 575 tx_ring_stats_list, TX_RING_STAT_SIZE}, 576 577 { DLADM_STAT_TOTAL, dlstat_total_stats, 578 i_dlstat_total_match, i_dlstat_total_stat_entry_diff, 579 offsetof(total_stat_entry_t, tse_stats), 580 total_stats_list, TOTAL_STAT_SIZE}, 581 582 { DLADM_STAT_AGGR_PORT, dlstat_aggr_port_stats, 583 i_dlstat_aggr_port_match, i_dlstat_aggr_port_stat_entry_diff, 584 offsetof(aggr_port_stat_entry_t, ape_stats), 585 aggr_port_stats_list, AGGR_PORT_STAT_SIZE}, 586 /* 587 * We don't support -i <interval> query with misc stats. Several table fields 588 * are left uninitialized thus. 589 */ 590 { DLADM_STAT_MISC, dlstat_misc_stats, 591 NULL, NULL, 592 0, 593 misc_stats_list, MISC_STAT_SIZE} 594 }; 595 596 /* Internal functions */ 597 static void * 598 dlstat_diff_stats(void *arg1, void *arg2, dladm_stat_type_t stattype) 599 { 600 return (dladm_stat_table[stattype].ds_diffstat(arg1, arg2)); 601 } 602 603 static boolean_t 604 dlstat_match_stats(void *arg1, void *arg2, dladm_stat_type_t stattype) 605 { 606 return (dladm_stat_table[stattype].ds_matchstat(arg1, arg2)); 607 } 608 609 /* Diff between two stats */ 610 static void 611 i_dlstat_diff_stats(void *diff, void *op1, void *op2, 612 stat_info_t stats_list[], uint_t size) 613 { 614 int i; 615 616 for (i = 0; i < size; i++) { 617 uint64_t *op1_val = (void *) 618 ((uchar_t *)op1 + stats_list[i].si_offset); 619 uint64_t *op2_val = (void *) 620 ((uchar_t *)op2 + stats_list[i].si_offset); 621 uint64_t *diff_val = (void *) 622 ((uchar_t *)diff + stats_list[i].si_offset); 623 624 *diff_val = DIFF_STAT(*op1_val, *op2_val); 625 } 626 } 627 628 /* 629 * Perform diff = s1 - s2, where diff, s1, s2 are structure objects of same 630 * datatype. slist is list of offsets of the fields within the structure. 631 */ 632 #define DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) { \ 633 if (s2 == NULL) { \ 634 bcopy(&s1->f, &diff->f, sizeof (s1->f)); \ 635 } else { \ 636 i_dlstat_diff_stats(&diff->f, &s1->f, \ 637 &s2->f, slist, sz); \ 638 } \ 639 } 640 641 /* Sum two stats */ 642 static void 643 i_dlstat_sum_stats(void *sum, void *op1, void *op2, 644 stat_info_t stats_list[], uint_t size) 645 { 646 int i; 647 648 for (i = 0; i < size; i++) { 649 uint64_t *op1_val = (void *) 650 ((uchar_t *)op1 + stats_list[i].si_offset); 651 uint64_t *op2_val = (void *) 652 ((uchar_t *)op2 + stats_list[i].si_offset); 653 uint64_t *sum_val = (void *) 654 ((uchar_t *)sum + stats_list[i].si_offset); 655 656 *sum_val = *op1_val + *op2_val; 657 } 658 } 659 660 /* Look up kstat value */ 661 static void 662 i_dlstat_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, void *stats, 663 stat_info_t stats_list[], uint_t size) 664 { 665 int i; 666 667 if (kstat_read(kcp, ksp, NULL) == -1) 668 return; 669 670 for (i = 0; i < size; i++) { 671 uint64_t *val = (void *) 672 ((uchar_t *)stats + stats_list[i].si_offset); 673 674 if (dladm_kstat_value(ksp, stats_list[i].si_name, 675 KSTAT_DATA_UINT64, val) < 0) 676 return; 677 } 678 } 679 680 /* Append linked list list1 to linked list list2 and return resulting list */ 681 static dladm_stat_chain_t * 682 i_dlstat_join_lists(dladm_stat_chain_t *list1, dladm_stat_chain_t *list2) 683 { 684 dladm_stat_chain_t *curr; 685 686 if (list1 == NULL) 687 return (list2); 688 689 /* list1 has at least one element, find last element in list1 */ 690 curr = list1; 691 while (curr->dc_next != NULL) 692 curr = curr->dc_next; 693 694 curr->dc_next = list2; 695 return (list1); 696 } 697 698 uint_t default_idlist[] = {0}; 699 uint_t default_idlist_size = 1; 700 701 typedef enum { 702 DLSTAT_RX_RING_IDLIST, 703 DLSTAT_TX_RING_IDLIST, 704 DLSTAT_RX_HWLANE_IDLIST, 705 DLSTAT_TX_HWLANE_IDLIST, 706 DLSTAT_FANOUT_IDLIST 707 } dlstat_idlist_type_t; 708 709 void 710 dladm_sort_index_list(uint_t idlist[], uint_t size) 711 { 712 int i, j; 713 714 for (j = 1; j < size; j++) { 715 int key = idlist[j]; 716 for (i = j - 1; (i >= 0) && (idlist[i] > key); i--) 717 idlist[i + 1] = idlist[i]; 718 idlist[i + 1] = key; 719 } 720 } 721 722 /* Support for legacy drivers */ 723 void 724 i_query_legacy_stats(dladm_handle_t dh, const char *linkname, pktsum_t *stats) 725 { 726 kstat_t *ksp; 727 728 bzero(stats, sizeof (*stats)); 729 730 if (dladm_dld_kcp(dh) == NULL) 731 return; 732 733 ksp = dladm_kstat_lookup(dladm_dld_kcp(dh), "link", 0, linkname, NULL); 734 735 if (ksp != NULL) 736 dladm_get_stats(dladm_dld_kcp(dh), ksp, stats); 737 } 738 739 void * 740 i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh, const char *linkname) 741 { 742 dladm_stat_chain_t *head = NULL; 743 pktsum_t stats; 744 rx_lane_stat_entry_t *rx_lane_stat_entry; 745 746 bzero(&stats, sizeof (pktsum_t)); 747 748 /* Query for dls stats */ 749 i_query_legacy_stats(dh, linkname, &stats); 750 751 /* Convert to desired data type */ 752 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 753 if (rx_lane_stat_entry == NULL) 754 goto done; 755 756 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 757 rx_lane_stat_entry->rle_id = L_SWLANE; 758 759 rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets; 760 rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets; 761 rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes; 762 763 /* Allocate memory for wrapper */ 764 head = malloc(sizeof (dladm_stat_chain_t)); 765 if (head == NULL) { 766 free(rx_lane_stat_entry); 767 goto done; 768 } 769 770 head->dc_statentry = rx_lane_stat_entry; 771 head->dc_next = NULL; 772 done: 773 return (head); 774 } 775 776 void * 777 i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh, const char *linkname) 778 { 779 dladm_stat_chain_t *head = NULL; 780 pktsum_t stats; 781 tx_lane_stat_entry_t *tx_lane_stat_entry; 782 783 bzero(&stats, sizeof (pktsum_t)); 784 785 /* Query for dls stats */ 786 i_query_legacy_stats(dh, linkname, &stats); 787 788 /* Convert to desired data type */ 789 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 790 if (tx_lane_stat_entry == NULL) 791 goto done; 792 793 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 794 tx_lane_stat_entry->tle_id = L_SWLANE; 795 796 tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets; 797 tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes; 798 799 /* Allocate memory for wrapper */ 800 head = malloc(sizeof (dladm_stat_chain_t)); 801 if (head == NULL) { 802 free(tx_lane_stat_entry); 803 goto done; 804 } 805 806 head->dc_statentry = tx_lane_stat_entry; 807 head->dc_next = NULL; 808 done: 809 return (head); 810 } 811 812 /* 813 * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids) 814 * for a given data-link (or mac client). We could then query for specific 815 * kstats based on these ring-ids (lane-ids). 816 * Ring-ids (or lane-ids) could be returned like any other link properties 817 * queried by dladm show-linkprop. However, non-global zones do not have 818 * access to this information today. 819 * We thus opt for an implementation that relies heavily on kstat internals: 820 * i_dlstat_*search routines and i_dlstat_get_idlist. 821 */ 822 /* rx hwlane specific */ 823 static boolean_t 824 i_dlstat_rx_hwlane_search(kstat_t *ksp) 825 { 826 return (ksp->ks_instance == 0 && 827 strstr(ksp->ks_name, "mac_rx") != 0 && 828 strstr(ksp->ks_name, "hwlane") != 0 && 829 strstr(ksp->ks_name, "fanout") == 0 && 830 strcmp(ksp->ks_class, "net") == 0); 831 } 832 833 /* tx hwlane specific */ 834 static boolean_t 835 i_dlstat_tx_hwlane_search(kstat_t *ksp) 836 { 837 return (ksp->ks_instance == 0 && 838 strstr(ksp->ks_name, "mac_tx") != 0 && 839 strstr(ksp->ks_name, "hwlane") != 0 && 840 strcmp(ksp->ks_class, "net") == 0); 841 } 842 843 /* rx fanout specific */ 844 static boolean_t 845 i_dlstat_fanout_search(kstat_t *ksp) 846 { 847 return (ksp->ks_instance == 0 && 848 strstr(ksp->ks_name, "mac_rx") != 0 && 849 strstr(ksp->ks_name, "swlane") != 0 && 850 strstr(ksp->ks_name, "fanout") != 0 && 851 strcmp(ksp->ks_class, "net") == 0); 852 } 853 854 /* rx ring specific */ 855 static boolean_t 856 i_dlstat_rx_ring_search(kstat_t *ksp) 857 { 858 return (ksp->ks_instance == 0 && 859 strstr(ksp->ks_name, "mac_rx") != 0 && 860 strstr(ksp->ks_name, "ring") != 0 && 861 strcmp(ksp->ks_class, "net") == 0); 862 } 863 864 /* tx ring specific */ 865 static boolean_t 866 i_dlstat_tx_ring_search(kstat_t *ksp) 867 { 868 return (ksp->ks_instance == 0) && 869 strstr(ksp->ks_name, "mac_tx") != 0 && 870 strstr(ksp->ks_name, "ring") != 0 && 871 strcmp(ksp->ks_class, "net") == 0; 872 } 873 874 typedef boolean_t dladm_search_kstat_t(kstat_t *); 875 typedef struct dladm_extract_idlist_s { 876 dlstat_idlist_type_t di_type; 877 char *di_prefix; 878 dladm_search_kstat_t *di_searchkstat; 879 } dladm_extract_idlist_t; 880 881 static dladm_extract_idlist_t dladm_extract_idlist[] = { 882 { DLSTAT_RX_RING_IDLIST, DLSTAT_MAC_RX_RING, 883 i_dlstat_rx_ring_search}, 884 { DLSTAT_TX_RING_IDLIST, DLSTAT_MAC_TX_RING, 885 i_dlstat_tx_ring_search}, 886 { DLSTAT_RX_HWLANE_IDLIST, DLSTAT_MAC_RX_HWLANE, 887 i_dlstat_rx_hwlane_search}, 888 { DLSTAT_TX_HWLANE_IDLIST, DLSTAT_MAC_TX_HWLANE, 889 i_dlstat_tx_hwlane_search}, 890 { DLSTAT_FANOUT_IDLIST, DLSTAT_MAC_FANOUT, 891 i_dlstat_fanout_search} 892 }; 893 894 static void 895 i_dlstat_get_idlist(dladm_handle_t handle, const char *modname, 896 dlstat_idlist_type_t idlist_type, 897 uint_t idlist[], uint_t *size) 898 { 899 kstat_ctl_t *kcp = dladm_dld_kcp(handle); 900 kstat_t *ksp; 901 char *prefix; 902 int prefixlen; 903 boolean_t (*fptr_searchkstat)(kstat_t *); 904 905 *size = 0; 906 907 if (kcp == NULL) { 908 warn("kstat_open operation failed"); 909 return; 910 } 911 912 prefix = dladm_extract_idlist[idlist_type].di_prefix; 913 fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat; 914 prefixlen = strlen(prefix); 915 for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 916 if ((strcmp(ksp->ks_module, modname) == 0) && 917 fptr_searchkstat(ksp)) { 918 idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]); 919 } 920 } 921 dladm_sort_index_list(idlist, *size); 922 } 923 924 static dladm_stat_chain_t * 925 i_dlstat_query_stats(dladm_handle_t handle, const char *modname, 926 const char *prefix, uint_t idlist[], uint_t idlist_size, 927 void * (*fn)(kstat_ctl_t *, kstat_t *, int)) 928 { 929 kstat_t *ksp; 930 char statname[MAXLINKNAMELEN]; 931 int i = 0; 932 dladm_stat_chain_t *head = NULL, *prev = NULL; 933 dladm_stat_chain_t *curr; 934 935 if (dladm_dld_kcp(handle) == NULL) { 936 warn("kstat_open operation failed"); 937 return (NULL); 938 } 939 940 for (i = 0; i < idlist_size; i++) { 941 uint_t index = idlist[i]; 942 943 (void) snprintf(statname, sizeof (statname), "%s%d", prefix, 944 index); 945 946 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), modname, 0, 947 statname, NULL); 948 if (ksp == NULL) 949 continue; 950 951 curr = malloc(sizeof (dladm_stat_chain_t)); 952 if (curr == NULL) 953 break; 954 955 curr->dc_statentry = fn(dladm_dld_kcp(handle), ksp, index); 956 if (curr->dc_statentry == NULL) { 957 free(curr); 958 break; 959 } 960 961 (void) strlcpy(curr->dc_statheader, statname, 962 sizeof (curr->dc_statheader)); 963 curr->dc_next = NULL; 964 965 if (head == NULL) /* First node */ 966 head = curr; 967 else 968 prev->dc_next = curr; 969 970 prev = curr; 971 } 972 done: 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 /*ARGSUSED*/ 1053 static void * 1054 i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1055 { 1056 rx_lane_stat_entry_t *rx_lane_stat_entry; 1057 1058 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1059 if (rx_lane_stat_entry == NULL) 1060 goto done; 1061 1062 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1063 rx_lane_stat_entry->rle_id = L_SWLANE; 1064 1065 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1066 rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 1067 1068 rx_lane_stat_entry->rle_stats.rl_ipackets = 1069 rx_lane_stat_entry->rle_stats.rl_intrs; 1070 rx_lane_stat_entry->rle_stats.rl_rbytes = 1071 rx_lane_stat_entry->rle_stats.rl_intrbytes; 1072 done: 1073 return (rx_lane_stat_entry); 1074 } 1075 1076 /*ARGSUSED*/ 1077 static void * 1078 i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1079 { 1080 rx_lane_stat_entry_t *local_stat_entry; 1081 rx_lane_stat_entry_t *rx_lane_stat_entry; 1082 1083 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1084 if (rx_lane_stat_entry == NULL) 1085 goto done; 1086 1087 local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1088 if (local_stat_entry == NULL) 1089 goto done; 1090 1091 local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1092 local_stat_entry->rle_id = L_LOCAL; 1093 1094 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1095 rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 1096 1097 local_stat_entry->rle_stats.rl_ipackets = 1098 rx_lane_stat_entry->rle_stats.rl_lclpackets; 1099 local_stat_entry->rle_stats.rl_rbytes = 1100 rx_lane_stat_entry->rle_stats.rl_lclbytes; 1101 1102 done: 1103 free(rx_lane_stat_entry); 1104 return (local_stat_entry); 1105 } 1106 1107 static dladm_stat_chain_t * 1108 i_dlstat_rx_local_stats(dladm_handle_t handle, const char *linkname) 1109 { 1110 dladm_stat_chain_t *local_stats = NULL; 1111 1112 local_stats = i_dlstat_query_stats(handle, linkname, 1113 DLSTAT_MAC_RX_SWLANE, 1114 default_idlist, default_idlist_size, 1115 i_dlstat_rx_local_retrieve_stat); 1116 1117 if (local_stats != NULL) { 1118 (void) strlcpy(local_stats->dc_statheader, "mac_rx_local", 1119 sizeof (local_stats->dc_statheader)); 1120 } 1121 return (local_stats); 1122 } 1123 1124 static dladm_stat_chain_t * 1125 i_dlstat_rx_bcast_stats(dladm_handle_t handle, const char *linkname) 1126 { 1127 misc_stat_entry_t *misc_stat_entry; 1128 dladm_stat_chain_t *head = NULL; 1129 rx_lane_stat_entry_t *rx_lane_stat_entry; 1130 1131 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1132 if (misc_stat_entry == NULL) 1133 goto done; 1134 1135 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1136 if (rx_lane_stat_entry == NULL) 1137 goto done; 1138 1139 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1140 rx_lane_stat_entry->rle_id = L_BCAST; 1141 1142 rx_lane_stat_entry->rle_stats.rl_ipackets = 1143 misc_stat_entry->mse_stats.ms_brdcstrcv + 1144 misc_stat_entry->mse_stats.ms_multircv; 1145 rx_lane_stat_entry->rle_stats.rl_intrs = 1146 misc_stat_entry->mse_stats.ms_brdcstrcv + 1147 misc_stat_entry->mse_stats.ms_multircv; 1148 rx_lane_stat_entry->rle_stats.rl_rbytes = 1149 misc_stat_entry->mse_stats.ms_brdcstrcvbytes + 1150 misc_stat_entry->mse_stats.ms_multircvbytes; 1151 1152 head = malloc(sizeof (dladm_stat_chain_t)); 1153 if (head == NULL) { 1154 free(rx_lane_stat_entry); 1155 goto done; 1156 } 1157 1158 head->dc_statentry = rx_lane_stat_entry; 1159 head->dc_next = NULL; 1160 1161 free(misc_stat_entry); 1162 done: 1163 return (head); 1164 } 1165 1166 static dladm_stat_chain_t * 1167 i_dlstat_rx_defunctlane_stats(dladm_handle_t handle, const char *linkname) 1168 { 1169 misc_stat_entry_t *misc_stat_entry; 1170 dladm_stat_chain_t *head = NULL; 1171 rx_lane_stat_entry_t *rx_lane_stat_entry; 1172 1173 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1174 if (misc_stat_entry == NULL) 1175 goto done; 1176 1177 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1178 if (rx_lane_stat_entry == NULL) 1179 goto done; 1180 1181 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1182 rx_lane_stat_entry->rle_id = L_DFNCT; 1183 1184 rx_lane_stat_entry->rle_stats.rl_ipackets = 1185 misc_stat_entry->mse_stats.ms_ipackets; 1186 rx_lane_stat_entry->rle_stats.rl_rbytes = 1187 misc_stat_entry->mse_stats.ms_rbytes; 1188 rx_lane_stat_entry->rle_stats.rl_intrs = 1189 misc_stat_entry->mse_stats.ms_intrs; 1190 rx_lane_stat_entry->rle_stats.rl_polls = 1191 misc_stat_entry->mse_stats.ms_polls; 1192 rx_lane_stat_entry->rle_stats.rl_sdrops = 1193 misc_stat_entry->mse_stats.ms_rxsdrops; 1194 rx_lane_stat_entry->rle_stats.rl_chl10 = 1195 misc_stat_entry->mse_stats.ms_chainunder10; 1196 rx_lane_stat_entry->rle_stats.rl_ch10_50 = 1197 misc_stat_entry->mse_stats.ms_chain10to50; 1198 rx_lane_stat_entry->rle_stats.rl_chg50 = 1199 misc_stat_entry->mse_stats.ms_chainover50; 1200 1201 head = malloc(sizeof (dladm_stat_chain_t)); 1202 if (head == NULL) { 1203 free(rx_lane_stat_entry); 1204 goto done; 1205 } 1206 1207 head->dc_statentry = rx_lane_stat_entry; 1208 head->dc_next = NULL; 1209 1210 done: 1211 return (head); 1212 } 1213 1214 static dladm_stat_chain_t * 1215 i_dlstat_rx_hwlane_stats(dladm_handle_t handle, const char *linkname) 1216 { 1217 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1218 uint_t rx_hwlane_idlist_size; 1219 1220 i_dlstat_get_idlist(handle, linkname, DLSTAT_RX_HWLANE_IDLIST, 1221 rx_hwlane_idlist, &rx_hwlane_idlist_size); 1222 1223 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_RX_HWLANE, 1224 rx_hwlane_idlist, rx_hwlane_idlist_size, 1225 i_dlstat_rx_hwlane_retrieve_stat)); 1226 } 1227 1228 /*ARGSUSED*/ 1229 static dladm_stat_chain_t * 1230 i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid, 1231 const char *linkname) 1232 { 1233 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_RX_SWLANE, 1234 default_idlist, default_idlist_size, 1235 i_dlstat_rx_swlane_retrieve_stat)); 1236 } 1237 1238 void * 1239 dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 1240 { 1241 dladm_stat_chain_t *head = NULL; 1242 dladm_stat_chain_t *local_stats = NULL; 1243 dladm_stat_chain_t *bcast_stats = NULL; 1244 dladm_stat_chain_t *defunctlane_stats = NULL; 1245 dladm_stat_chain_t *lane_stats = NULL; 1246 char linkname[MAXLINKNAMELEN]; 1247 boolean_t is_legacy_driver; 1248 1249 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1250 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1251 goto done; 1252 } 1253 1254 /* Check if it is legacy driver */ 1255 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 1256 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 1257 goto done; 1258 } 1259 1260 if (is_legacy_driver) { 1261 head = i_dlstat_legacy_rx_lane_stats(dh, linkname); 1262 goto done; 1263 } 1264 1265 local_stats = i_dlstat_rx_local_stats(dh, linkname); 1266 bcast_stats = i_dlstat_rx_bcast_stats(dh, linkname); 1267 defunctlane_stats = i_dlstat_rx_defunctlane_stats(dh, linkname); 1268 lane_stats = i_dlstat_rx_hwlane_stats(dh, linkname); 1269 if (lane_stats == NULL) 1270 lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname); 1271 1272 head = i_dlstat_join_lists(local_stats, bcast_stats); 1273 head = i_dlstat_join_lists(head, defunctlane_stats); 1274 head = i_dlstat_join_lists(head, lane_stats); 1275 done: 1276 return (head); 1277 } 1278 1279 /* Tx lane statistic specific functions */ 1280 static boolean_t 1281 i_dlstat_tx_lane_match(void *arg1, void *arg2) 1282 { 1283 tx_lane_stat_entry_t *s1 = arg1; 1284 tx_lane_stat_entry_t *s2 = arg2; 1285 1286 return (s1->tle_index == s2->tle_index && 1287 s1->tle_id == s2->tle_id); 1288 } 1289 1290 static void * 1291 i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2) 1292 { 1293 tx_lane_stat_entry_t *s1 = arg1; 1294 tx_lane_stat_entry_t *s2 = arg2; 1295 tx_lane_stat_entry_t *diff_entry; 1296 1297 diff_entry = malloc(sizeof (tx_lane_stat_entry_t)); 1298 if (diff_entry == NULL) 1299 goto done; 1300 1301 diff_entry->tle_index = s1->tle_index; 1302 diff_entry->tle_id = s1->tle_id; 1303 1304 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list, 1305 TX_LANE_STAT_SIZE); 1306 1307 done: 1308 return (diff_entry); 1309 } 1310 1311 static void * 1312 i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1313 { 1314 tx_lane_stat_entry_t *tx_lane_stat_entry; 1315 1316 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1317 if (tx_lane_stat_entry == NULL) 1318 goto done; 1319 1320 tx_lane_stat_entry->tle_index = i; 1321 tx_lane_stat_entry->tle_id = L_HWLANE; 1322 1323 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 1324 tx_lane_stats_list, TX_LANE_STAT_SIZE); 1325 1326 done: 1327 return (tx_lane_stat_entry); 1328 } 1329 1330 /*ARGSUSED*/ 1331 static void * 1332 i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1333 { 1334 tx_lane_stat_entry_t *tx_lane_stat_entry; 1335 1336 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1337 if (tx_lane_stat_entry == NULL) 1338 goto done; 1339 1340 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1341 tx_lane_stat_entry->tle_id = L_SWLANE; 1342 1343 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 1344 tx_lane_stats_list, TX_LANE_STAT_SIZE); 1345 1346 done: 1347 return (tx_lane_stat_entry); 1348 } 1349 1350 static dladm_stat_chain_t * 1351 i_dlstat_tx_bcast_stats(dladm_handle_t handle, const char *linkname) 1352 { 1353 misc_stat_entry_t *misc_stat_entry; 1354 dladm_stat_chain_t *head = NULL; 1355 tx_lane_stat_entry_t *tx_lane_stat_entry; 1356 1357 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1358 if (misc_stat_entry == NULL) 1359 goto done; 1360 1361 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1362 if (tx_lane_stat_entry == NULL) 1363 goto done; 1364 1365 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1366 tx_lane_stat_entry->tle_id = L_BCAST; 1367 1368 tx_lane_stat_entry->tle_stats.tl_opackets = 1369 misc_stat_entry->mse_stats.ms_brdcstxmt + 1370 misc_stat_entry->mse_stats.ms_multixmt; 1371 1372 tx_lane_stat_entry->tle_stats.tl_obytes = 1373 misc_stat_entry->mse_stats.ms_brdcstxmtbytes + 1374 misc_stat_entry->mse_stats.ms_multixmtbytes; 1375 1376 head = malloc(sizeof (dladm_stat_chain_t)); 1377 if (head == NULL) { 1378 free(tx_lane_stat_entry); 1379 goto done; 1380 } 1381 1382 head->dc_statentry = tx_lane_stat_entry; 1383 head->dc_next = NULL; 1384 1385 free(misc_stat_entry); 1386 done: 1387 return (head); 1388 } 1389 1390 static dladm_stat_chain_t * 1391 i_dlstat_tx_defunctlane_stats(dladm_handle_t handle, const char *linkname) 1392 { 1393 misc_stat_entry_t *misc_stat_entry; 1394 dladm_stat_chain_t *head = NULL; 1395 tx_lane_stat_entry_t *tx_lane_stat_entry; 1396 1397 misc_stat_entry = i_dlstat_misc_stats(handle, linkname); 1398 if (misc_stat_entry == NULL) 1399 goto done; 1400 1401 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1402 if (tx_lane_stat_entry == NULL) 1403 goto done; 1404 1405 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1406 tx_lane_stat_entry->tle_id = L_DFNCT; 1407 1408 tx_lane_stat_entry->tle_stats.tl_opackets = 1409 misc_stat_entry->mse_stats.ms_opackets; 1410 tx_lane_stat_entry->tle_stats.tl_obytes = 1411 misc_stat_entry->mse_stats.ms_obytes; 1412 tx_lane_stat_entry->tle_stats.tl_sdrops = 1413 misc_stat_entry->mse_stats.ms_txsdrops; 1414 1415 head = malloc(sizeof (dladm_stat_chain_t)); 1416 if (head == NULL) { 1417 free(tx_lane_stat_entry); 1418 goto done; 1419 } 1420 1421 head->dc_statentry = tx_lane_stat_entry; 1422 head->dc_next = NULL; 1423 1424 done: 1425 return (head); 1426 } 1427 1428 static dladm_stat_chain_t * 1429 i_dlstat_tx_hwlane_stats(dladm_handle_t handle, const char *linkname) 1430 { 1431 uint_t tx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1432 uint_t tx_hwlane_idlist_size; 1433 1434 i_dlstat_get_idlist(handle, linkname, DLSTAT_TX_HWLANE_IDLIST, 1435 tx_hwlane_idlist, &tx_hwlane_idlist_size); 1436 1437 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_TX_HWLANE, 1438 tx_hwlane_idlist, tx_hwlane_idlist_size, 1439 i_dlstat_tx_hwlane_retrieve_stat)); 1440 } 1441 1442 /*ARGSUSED*/ 1443 static dladm_stat_chain_t * 1444 i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid, 1445 const char *linkname) 1446 { 1447 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_TX_SWLANE, 1448 default_idlist, default_idlist_size, 1449 i_dlstat_tx_swlane_retrieve_stat)); 1450 } 1451 1452 void * 1453 dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 1454 { 1455 dladm_stat_chain_t *head = NULL; 1456 dladm_stat_chain_t *bcast_stats = NULL; 1457 dladm_stat_chain_t *defunctlane_stats = NULL; 1458 dladm_stat_chain_t *lane_stats; 1459 char linkname[MAXLINKNAMELEN]; 1460 boolean_t is_legacy_driver; 1461 1462 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1463 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1464 goto done; 1465 } 1466 1467 /* Check if it is legacy driver */ 1468 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 1469 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 1470 goto done; 1471 } 1472 1473 if (is_legacy_driver) { 1474 head = i_dlstat_legacy_tx_lane_stats(dh, linkname); 1475 goto done; 1476 } 1477 1478 bcast_stats = i_dlstat_tx_bcast_stats(dh, linkname); 1479 defunctlane_stats = i_dlstat_tx_defunctlane_stats(dh, linkname); 1480 lane_stats = i_dlstat_tx_hwlane_stats(dh, linkname); 1481 if (lane_stats == NULL) 1482 lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname); 1483 1484 head = i_dlstat_join_lists(bcast_stats, defunctlane_stats); 1485 head = i_dlstat_join_lists(head, lane_stats); 1486 1487 done: 1488 return (head); 1489 } 1490 1491 /* Rx lane total statistic specific functions */ 1492 void * 1493 dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1494 { 1495 dladm_stat_chain_t *total_head = NULL; 1496 dladm_stat_chain_t *rx_lane_head, *curr; 1497 rx_lane_stat_entry_t *total_stats; 1498 1499 /* Get per rx lane stats */ 1500 rx_lane_head = dlstat_rx_lane_stats(dh, linkid); 1501 if (rx_lane_head == NULL) 1502 goto done; 1503 1504 total_stats = calloc(1, sizeof (rx_lane_stat_entry_t)); 1505 if (total_stats == NULL) 1506 goto done; 1507 1508 total_stats->rle_index = DLSTAT_INVALID_ENTRY; 1509 total_stats->rle_id = DLSTAT_INVALID_ENTRY; 1510 1511 for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) { 1512 rx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 1513 1514 i_dlstat_sum_stats(&total_stats->rle_stats, 1515 &curr_lane_stats->rle_stats, &total_stats->rle_stats, 1516 rx_lane_stats_list, RX_LANE_STAT_SIZE); 1517 } 1518 1519 total_head = malloc(sizeof (dladm_stat_chain_t)); 1520 if (total_head == NULL) { 1521 free(total_stats); 1522 goto done; 1523 } 1524 1525 total_head->dc_statentry = total_stats; 1526 (void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total", 1527 sizeof (total_head->dc_statheader)); 1528 total_head->dc_next = NULL; 1529 free(rx_lane_head); 1530 1531 done: 1532 return (total_head); 1533 } 1534 1535 /* Tx lane total statistic specific functions */ 1536 void * 1537 dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1538 { 1539 dladm_stat_chain_t *total_head = NULL; 1540 dladm_stat_chain_t *tx_lane_head, *curr; 1541 tx_lane_stat_entry_t *total_stats; 1542 1543 /* Get per tx lane stats */ 1544 tx_lane_head = dlstat_tx_lane_stats(dh, linkid); 1545 if (tx_lane_head == NULL) 1546 goto done; 1547 1548 total_stats = calloc(1, sizeof (tx_lane_stat_entry_t)); 1549 if (total_stats == NULL) 1550 goto done; 1551 1552 total_stats->tle_index = DLSTAT_INVALID_ENTRY; 1553 total_stats->tle_id = DLSTAT_INVALID_ENTRY; 1554 1555 for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) { 1556 tx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 1557 1558 i_dlstat_sum_stats(&total_stats->tle_stats, 1559 &curr_lane_stats->tle_stats, &total_stats->tle_stats, 1560 tx_lane_stats_list, TX_LANE_STAT_SIZE); 1561 } 1562 1563 total_head = malloc(sizeof (dladm_stat_chain_t)); 1564 if (total_head == NULL) { 1565 free(total_stats); 1566 goto done; 1567 } 1568 1569 total_head->dc_statentry = total_stats; 1570 (void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total", 1571 sizeof (total_head->dc_statheader)); 1572 total_head->dc_next = NULL; 1573 free(tx_lane_head); 1574 1575 done: 1576 return (total_head); 1577 } 1578 1579 /* Fanout specific functions */ 1580 static boolean_t 1581 i_dlstat_fanout_match(void *arg1, void *arg2) 1582 { 1583 fanout_stat_entry_t *s1 = arg1; 1584 fanout_stat_entry_t *s2 = arg2; 1585 1586 return (s1->fe_index == s2->fe_index && 1587 s1->fe_id == s2->fe_id && 1588 s1->fe_foutindex == s2->fe_foutindex); 1589 } 1590 1591 static void * 1592 i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2) 1593 { 1594 fanout_stat_entry_t *s1 = arg1; 1595 fanout_stat_entry_t *s2 = arg2; 1596 fanout_stat_entry_t *diff_entry; 1597 1598 diff_entry = malloc(sizeof (fanout_stat_entry_t)); 1599 if (diff_entry == NULL) 1600 goto done; 1601 1602 diff_entry->fe_index = s1->fe_index; 1603 diff_entry->fe_id = s1->fe_id; 1604 diff_entry->fe_foutindex = s1->fe_foutindex; 1605 1606 DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list, 1607 FANOUT_STAT_SIZE); 1608 1609 done: 1610 return (diff_entry); 1611 } 1612 1613 static void * 1614 i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1615 { 1616 fanout_stat_entry_t *fanout_stat_entry; 1617 1618 fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t)); 1619 if (fanout_stat_entry == NULL) 1620 goto done; 1621 1622 /* Set by the caller later */ 1623 fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY; 1624 fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY; 1625 1626 fanout_stat_entry->fe_foutindex = i; 1627 1628 i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats, 1629 fanout_stats_list, FANOUT_STAT_SIZE); 1630 1631 done: 1632 return (fanout_stat_entry); 1633 } 1634 1635 static void * 1636 i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid, 1637 uint_t idlist[], uint_t idlist_size, 1638 const char *modname, const char *prefix) 1639 { 1640 int i; 1641 char statprefix[MAXLINKNAMELEN]; 1642 char linkname[MAXLINKNAMELEN]; 1643 dladm_stat_chain_t *curr, *curr_head; 1644 dladm_stat_chain_t *head = NULL, *prev = NULL; 1645 uint_t fanout_idlist[MAX_RINGS_PER_GROUP]; 1646 uint_t fanout_idlist_size; 1647 1648 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1649 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1650 return (NULL); 1651 } 1652 1653 i_dlstat_get_idlist(dh, linkname, DLSTAT_FANOUT_IDLIST, 1654 fanout_idlist, &fanout_idlist_size); 1655 1656 for (i = 0; i < idlist_size; i++) { 1657 uint_t index = idlist[i]; 1658 1659 (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout", 1660 prefix, index); 1661 1662 curr_head = i_dlstat_query_stats(dh, modname, statprefix, 1663 fanout_idlist, fanout_idlist_size, 1664 i_dlstat_fanout_retrieve_stat); 1665 1666 if (curr_head == NULL) /* Last lane */ 1667 break; 1668 1669 if (head == NULL) /* First lane */ 1670 head = curr_head; 1671 else /* Link new lane list to end of previous lane list */ 1672 prev->dc_next = curr_head; 1673 1674 /* Walk new lane list and set ids */ 1675 for (curr = curr_head; curr != NULL; curr = curr->dc_next) { 1676 fanout_stat_entry_t *curr_stats = curr->dc_statentry; 1677 1678 curr_stats->fe_index = index; 1679 curr_stats->fe_id = L_HWLANE; 1680 /* 1681 * Save last pointer of previous linked list. 1682 * This pointer is used to chain linked lists 1683 * generated in each iteration. 1684 */ 1685 prev = curr; 1686 } 1687 } 1688 1689 return (head); 1690 } 1691 1692 void * 1693 dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid, 1694 const char *linkname) 1695 { 1696 return (i_dlstat_query_fanout_stats(dh, linkid, 1697 default_idlist, default_idlist_size, linkname, 1698 DLSTAT_MAC_RX_SWLANE)); 1699 } 1700 1701 void * 1702 dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid, 1703 const char *linkname) 1704 { 1705 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1706 uint_t rx_hwlane_idlist_size; 1707 1708 i_dlstat_get_idlist(dh, linkname, DLSTAT_RX_HWLANE_IDLIST, 1709 rx_hwlane_idlist, &rx_hwlane_idlist_size); 1710 1711 return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist, 1712 rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE)); 1713 } 1714 1715 void * 1716 dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid) 1717 { 1718 dladm_stat_chain_t *head = NULL; 1719 dladm_stat_chain_t *fout_hwlane_stats; 1720 dladm_stat_chain_t *fout_swlane_and_local_stats; 1721 fanout_stat_entry_t *fout_stats; 1722 char linkname[MAXLINKNAMELEN]; 1723 1724 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1725 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1726 goto done; 1727 } 1728 1729 fout_swlane_and_local_stats = 1730 dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname); 1731 fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname); 1732 1733 if (fout_swlane_and_local_stats == NULL) { 1734 head = fout_hwlane_stats; 1735 goto done; 1736 } 1737 1738 fout_stats = fout_swlane_and_local_stats->dc_statentry; 1739 1740 if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */ 1741 fout_stats->fe_id = L_LOCAL; 1742 fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 1743 } else { /* no hwlane, mix of local+sw classified */ 1744 fout_stats->fe_id = L_LCLSWLANE; 1745 fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 1746 } 1747 1748 fout_swlane_and_local_stats->dc_next = fout_hwlane_stats; 1749 head = fout_swlane_and_local_stats; 1750 1751 done: 1752 return (head); 1753 } 1754 1755 /* Rx ring statistic specific functions */ 1756 static boolean_t 1757 i_dlstat_rx_ring_match(void *arg1, void *arg2) 1758 { 1759 rx_lane_stat_entry_t *s1 = arg1; 1760 rx_lane_stat_entry_t *s2 = arg2; 1761 1762 return (s1->rle_index == s2->rle_index); 1763 } 1764 1765 static void * 1766 i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2) 1767 { 1768 ring_stat_entry_t *s1 = arg1; 1769 ring_stat_entry_t *s2 = arg2; 1770 ring_stat_entry_t *diff_entry; 1771 1772 diff_entry = malloc(sizeof (ring_stat_entry_t)); 1773 if (diff_entry == NULL) 1774 goto done; 1775 1776 diff_entry->re_index = s1->re_index; 1777 1778 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list, 1779 RX_RING_STAT_SIZE); 1780 1781 done: 1782 return (diff_entry); 1783 } 1784 1785 static void * 1786 i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1787 { 1788 ring_stat_entry_t *rx_ring_stat_entry; 1789 1790 rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 1791 if (rx_ring_stat_entry == NULL) 1792 goto done; 1793 1794 rx_ring_stat_entry->re_index = i; 1795 1796 i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats, 1797 rx_ring_stats_list, RX_RING_STAT_SIZE); 1798 1799 done: 1800 return (rx_ring_stat_entry); 1801 } 1802 1803 void * 1804 dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 1805 { 1806 uint_t rx_ring_idlist[MAX_RINGS_PER_GROUP]; 1807 uint_t rx_ring_idlist_size; 1808 dladm_phys_attr_t dpa; 1809 char linkname[MAXLINKNAMELEN]; 1810 char *modname; 1811 datalink_class_t class; 1812 1813 /* 1814 * kstats corresponding to physical device rings continue to use 1815 * device names even if the link is renamed using dladm rename-link. 1816 * Thus, given a linkid, we lookup the physical device name. 1817 * However, if an aggr is renamed, kstats corresponding to its 1818 * pseudo rings are renamed as well. 1819 */ 1820 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 1821 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1822 return (NULL); 1823 } 1824 1825 if (class != DATALINK_CLASS_AGGR) { 1826 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 1827 DLADM_STATUS_OK) { 1828 return (NULL); 1829 } 1830 modname = dpa.dp_dev; 1831 } else 1832 modname = linkname; 1833 1834 i_dlstat_get_idlist(dh, modname, DLSTAT_RX_RING_IDLIST, 1835 rx_ring_idlist, &rx_ring_idlist_size); 1836 1837 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_RX_RING, 1838 rx_ring_idlist, rx_ring_idlist_size, 1839 i_dlstat_rx_ring_retrieve_stat)); 1840 } 1841 1842 /* Tx ring statistic specific functions */ 1843 static boolean_t 1844 i_dlstat_tx_ring_match(void *arg1, void *arg2) 1845 { 1846 tx_lane_stat_entry_t *s1 = arg1; 1847 tx_lane_stat_entry_t *s2 = arg2; 1848 1849 return (s1->tle_index == s2->tle_index); 1850 } 1851 1852 static void * 1853 i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2) 1854 { 1855 ring_stat_entry_t *s1 = arg1; 1856 ring_stat_entry_t *s2 = arg2; 1857 ring_stat_entry_t *diff_entry; 1858 1859 diff_entry = malloc(sizeof (ring_stat_entry_t)); 1860 if (diff_entry == NULL) 1861 goto done; 1862 1863 diff_entry->re_index = s1->re_index; 1864 1865 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list, 1866 TX_RING_STAT_SIZE); 1867 1868 done: 1869 return (diff_entry); 1870 } 1871 1872 static void * 1873 i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1874 { 1875 ring_stat_entry_t *tx_ring_stat_entry; 1876 1877 tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 1878 if (tx_ring_stat_entry == NULL) 1879 goto done; 1880 1881 tx_ring_stat_entry->re_index = i; 1882 1883 i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats, 1884 tx_ring_stats_list, TX_RING_STAT_SIZE); 1885 1886 done: 1887 return (tx_ring_stat_entry); 1888 } 1889 1890 void * 1891 dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 1892 { 1893 uint_t tx_ring_idlist[MAX_RINGS_PER_GROUP]; 1894 uint_t tx_ring_idlist_size; 1895 dladm_phys_attr_t dpa; 1896 char linkname[MAXLINKNAMELEN]; 1897 char *modname; 1898 datalink_class_t class; 1899 1900 /* 1901 * kstats corresponding to physical device rings continue to use 1902 * device names even if the link is renamed using dladm rename-link. 1903 * Thus, given a linkid, we lookup the physical device name. 1904 * However, if an aggr is renamed, kstats corresponding to its 1905 * pseudo rings are renamed as well. 1906 */ 1907 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 1908 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1909 return (NULL); 1910 } 1911 1912 if (class != DATALINK_CLASS_AGGR) { 1913 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 1914 DLADM_STATUS_OK) { 1915 return (NULL); 1916 } 1917 modname = dpa.dp_dev; 1918 } else 1919 modname = linkname; 1920 1921 i_dlstat_get_idlist(dh, modname, DLSTAT_TX_RING_IDLIST, 1922 tx_ring_idlist, &tx_ring_idlist_size); 1923 1924 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_TX_RING, 1925 tx_ring_idlist, tx_ring_idlist_size, 1926 i_dlstat_tx_ring_retrieve_stat)); 1927 } 1928 1929 /* Rx ring total statistic specific functions */ 1930 void * 1931 dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1932 { 1933 dladm_stat_chain_t *total_head = NULL; 1934 dladm_stat_chain_t *rx_ring_head, *curr; 1935 ring_stat_entry_t *total_stats; 1936 1937 /* Get per rx ring stats */ 1938 rx_ring_head = dlstat_rx_ring_stats(dh, linkid); 1939 if (rx_ring_head == NULL) 1940 goto done; 1941 1942 total_stats = calloc(1, sizeof (ring_stat_entry_t)); 1943 if (total_stats == NULL) 1944 goto done; 1945 1946 total_stats->re_index = DLSTAT_INVALID_ENTRY; 1947 1948 for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) { 1949 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 1950 1951 i_dlstat_sum_stats(&total_stats->re_stats, 1952 &curr_ring_stats->re_stats, &total_stats->re_stats, 1953 rx_ring_stats_list, RX_RING_STAT_SIZE); 1954 } 1955 1956 total_head = malloc(sizeof (dladm_stat_chain_t)); 1957 if (total_head == NULL) { 1958 free(total_stats); 1959 goto done; 1960 } 1961 1962 total_head->dc_statentry = total_stats; 1963 (void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total", 1964 sizeof (total_head->dc_statheader)); 1965 total_head->dc_next = NULL; 1966 free(rx_ring_head); 1967 1968 done: 1969 return (total_head); 1970 } 1971 1972 /* Tx ring total statistic specific functions */ 1973 void * 1974 dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1975 { 1976 dladm_stat_chain_t *total_head = NULL; 1977 dladm_stat_chain_t *tx_ring_head, *curr; 1978 ring_stat_entry_t *total_stats; 1979 1980 /* Get per tx ring stats */ 1981 tx_ring_head = dlstat_tx_ring_stats(dh, linkid); 1982 if (tx_ring_head == NULL) 1983 goto done; 1984 1985 total_stats = calloc(1, sizeof (ring_stat_entry_t)); 1986 if (total_stats == NULL) 1987 goto done; 1988 1989 total_stats->re_index = DLSTAT_INVALID_ENTRY; 1990 1991 for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) { 1992 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 1993 1994 i_dlstat_sum_stats(&total_stats->re_stats, 1995 &curr_ring_stats->re_stats, &total_stats->re_stats, 1996 tx_ring_stats_list, TX_RING_STAT_SIZE); 1997 } 1998 1999 total_head = malloc(sizeof (dladm_stat_chain_t)); 2000 if (total_head == NULL) { 2001 free(total_stats); 2002 goto done; 2003 } 2004 2005 total_head->dc_statentry = total_stats; 2006 (void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total", 2007 sizeof (total_head->dc_statheader)); 2008 total_head->dc_next = NULL; 2009 free(tx_ring_head); 2010 2011 done: 2012 return (total_head); 2013 } 2014 2015 /* Summary statistic specific functions */ 2016 /*ARGSUSED*/ 2017 static boolean_t 2018 i_dlstat_total_match(void *arg1, void *arg2) 2019 { 2020 /* Always single entry for total */ 2021 return (B_TRUE); 2022 } 2023 2024 static void * 2025 i_dlstat_total_stat_entry_diff(void *arg1, void *arg2) 2026 { 2027 total_stat_entry_t *s1 = arg1; 2028 total_stat_entry_t *s2 = arg2; 2029 total_stat_entry_t *diff_entry; 2030 2031 diff_entry = malloc(sizeof (total_stat_entry_t)); 2032 if (diff_entry == NULL) 2033 goto done; 2034 2035 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list, 2036 TOTAL_STAT_SIZE); 2037 2038 done: 2039 return (diff_entry); 2040 } 2041 2042 void * 2043 dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid) 2044 { 2045 dladm_stat_chain_t *head = NULL; 2046 dladm_stat_chain_t *rx_total; 2047 dladm_stat_chain_t *tx_total; 2048 total_stat_entry_t *total_stat_entry; 2049 rx_lane_stat_entry_t *rx_lane_stat_entry; 2050 tx_lane_stat_entry_t *tx_lane_stat_entry; 2051 2052 /* Get total rx lane stats */ 2053 rx_total = dlstat_rx_lane_total_stats(dh, linkid); 2054 if (rx_total == NULL) 2055 goto done; 2056 2057 /* Get total tx lane stats */ 2058 tx_total = dlstat_tx_lane_total_stats(dh, linkid); 2059 if (tx_total == NULL) 2060 goto done; 2061 2062 /* Build total stat */ 2063 total_stat_entry = calloc(1, sizeof (total_stat_entry_t)); 2064 if (total_stat_entry == NULL) 2065 goto done; 2066 2067 rx_lane_stat_entry = rx_total->dc_statentry; 2068 tx_lane_stat_entry = tx_total->dc_statentry; 2069 2070 /* Extract total rx ipackets, rbytes */ 2071 total_stat_entry->tse_stats.ts_ipackets = 2072 rx_lane_stat_entry->rle_stats.rl_ipackets; 2073 total_stat_entry->tse_stats.ts_rbytes = 2074 rx_lane_stat_entry->rle_stats.rl_rbytes; 2075 2076 /* Extract total tx opackets, obytes */ 2077 total_stat_entry->tse_stats.ts_opackets = 2078 tx_lane_stat_entry->tle_stats.tl_opackets; 2079 total_stat_entry->tse_stats.ts_obytes = 2080 tx_lane_stat_entry->tle_stats.tl_obytes; 2081 2082 head = malloc(sizeof (dladm_stat_chain_t)); 2083 if (head == NULL) { 2084 free(total_stat_entry); 2085 goto done; 2086 } 2087 2088 head->dc_statentry = total_stat_entry; 2089 (void) strlcpy(head->dc_statheader, "mac_lane_total", 2090 sizeof (head->dc_statheader)); 2091 head->dc_next = NULL; 2092 free(rx_total); 2093 free(tx_total); 2094 2095 done: 2096 return (head); 2097 } 2098 2099 /* Aggr total statistic(summed across all component ports) specific functions */ 2100 void * 2101 dlstat_aggr_total_stats(dladm_stat_chain_t *head) 2102 { 2103 dladm_stat_chain_t *curr; 2104 dladm_stat_chain_t *total_head; 2105 aggr_port_stat_entry_t *total_stats; 2106 2107 total_stats = calloc(1, sizeof (aggr_port_stat_entry_t)); 2108 if (total_stats == NULL) 2109 goto done; 2110 2111 total_stats->ape_portlinkid = DATALINK_INVALID_LINKID; 2112 2113 for (curr = head; curr != NULL; curr = curr->dc_next) { 2114 aggr_port_stat_entry_t *curr_aggr_port_stats; 2115 2116 curr_aggr_port_stats = curr->dc_statentry; 2117 2118 i_dlstat_sum_stats(&total_stats->ape_stats, 2119 &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats, 2120 aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 2121 } 2122 2123 total_head = malloc(sizeof (dladm_stat_chain_t)); 2124 if (total_head == NULL) { 2125 free(total_stats); 2126 goto done; 2127 } 2128 2129 total_head->dc_statentry = total_stats; 2130 total_head->dc_next = NULL; 2131 2132 done: 2133 return (total_head); 2134 } 2135 2136 /* Aggr port statistic specific functions */ 2137 static boolean_t 2138 i_dlstat_aggr_port_match(void *arg1, void *arg2) 2139 { 2140 aggr_port_stat_entry_t *s1 = arg1; 2141 aggr_port_stat_entry_t *s2 = arg2; 2142 2143 return (s1->ape_portlinkid == s2->ape_portlinkid); 2144 } 2145 2146 static void * 2147 i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2) 2148 { 2149 aggr_port_stat_entry_t *s1 = arg1; 2150 aggr_port_stat_entry_t *s2 = arg2; 2151 aggr_port_stat_entry_t *diff_entry; 2152 2153 diff_entry = malloc(sizeof (aggr_port_stat_entry_t)); 2154 if (diff_entry == NULL) 2155 goto done; 2156 2157 diff_entry->ape_portlinkid = s1->ape_portlinkid; 2158 2159 DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list, 2160 AGGR_PORT_STAT_SIZE); 2161 2162 done: 2163 return (diff_entry); 2164 } 2165 2166 /* 2167 * Query dls stats for the aggr port. This results in query for stats into 2168 * the corresponding device driver. 2169 */ 2170 static aggr_port_stat_entry_t * 2171 i_dlstat_single_port_stats(dladm_handle_t handle, const char *portname, 2172 datalink_id_t linkid) 2173 { 2174 kstat_t *ksp; 2175 char module[DLPI_LINKNAME_MAX]; 2176 uint_t instance; 2177 aggr_port_stat_entry_t *aggr_port_stat_entry = NULL; 2178 2179 if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK) 2180 goto done; 2181 2182 if (dladm_dld_kcp(handle) == NULL) { 2183 warn("kstat open operation failed"); 2184 return (NULL); 2185 } 2186 2187 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), module, instance, 2188 "mac", NULL); 2189 if (ksp == NULL) 2190 goto done; 2191 2192 aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t)); 2193 if (aggr_port_stat_entry == NULL) 2194 goto done; 2195 2196 /* Save port's linkid */ 2197 aggr_port_stat_entry->ape_portlinkid = linkid; 2198 2199 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, 2200 &aggr_port_stat_entry->ape_stats, 2201 aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 2202 done: 2203 return (aggr_port_stat_entry); 2204 } 2205 2206 void * 2207 dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid) 2208 { 2209 dladm_aggr_grp_attr_t ginfo; 2210 int i; 2211 dladm_aggr_port_attr_t *portp; 2212 dladm_phys_attr_t dpa; 2213 aggr_port_stat_entry_t *aggr_port_stat_entry; 2214 dladm_stat_chain_t *head = NULL, *prev = NULL, *curr; 2215 dladm_stat_chain_t *total_stats; 2216 2217 /* Get aggr info */ 2218 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2219 if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE) 2220 != DLADM_STATUS_OK) 2221 goto done; 2222 /* For every port that is member of this aggr do */ 2223 for (i = 0; i < ginfo.lg_nports; i++) { 2224 portp = &(ginfo.lg_ports[i]); 2225 if (dladm_phys_info(dh, portp->lp_linkid, &dpa, 2226 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { 2227 goto done; 2228 } 2229 2230 aggr_port_stat_entry = i_dlstat_single_port_stats(dh, 2231 dpa.dp_dev, portp->lp_linkid); 2232 2233 /* Create dladm_stat_chain_t object for this stat */ 2234 curr = malloc(sizeof (dladm_stat_chain_t)); 2235 if (curr == NULL) { 2236 free(aggr_port_stat_entry); 2237 goto done; 2238 } 2239 (void) strlcpy(curr->dc_statheader, dpa.dp_dev, 2240 sizeof (curr->dc_statheader)); 2241 curr->dc_statentry = aggr_port_stat_entry; 2242 curr->dc_next = NULL; 2243 2244 /* Chain this aggr port stat entry */ 2245 /* head of the stat list */ 2246 if (prev == NULL) 2247 head = curr; 2248 else 2249 prev->dc_next = curr; 2250 prev = curr; 2251 } 2252 2253 /* 2254 * Prepend the stat list with cumulative aggr stats i.e. summed over all 2255 * component ports 2256 */ 2257 total_stats = dlstat_aggr_total_stats(head); 2258 if (total_stats != NULL) { 2259 total_stats->dc_next = head; 2260 head = total_stats; 2261 } 2262 2263 done: 2264 free(ginfo.lg_ports); 2265 return (head); 2266 } 2267 2268 /* Misc stat specific functions */ 2269 void * 2270 dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid) 2271 { 2272 misc_stat_entry_t *misc_stat_entry; 2273 dladm_stat_chain_t *head = NULL; 2274 char linkname[MAXLINKNAMELEN]; 2275 2276 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 2277 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2278 goto done; 2279 } 2280 2281 misc_stat_entry = i_dlstat_misc_stats(dh, linkname); 2282 if (misc_stat_entry == NULL) 2283 goto done; 2284 2285 head = malloc(sizeof (dladm_stat_chain_t)); 2286 if (head == NULL) { 2287 free(misc_stat_entry); 2288 goto done; 2289 } 2290 2291 head->dc_statentry = misc_stat_entry; 2292 (void) strlcpy(head->dc_statheader, "mac_misc_stat", 2293 sizeof (head->dc_statheader)); 2294 head->dc_next = NULL; 2295 2296 done: 2297 return (head); 2298 } 2299 2300 /* Exported functions */ 2301 dladm_stat_chain_t * 2302 dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid, 2303 dladm_stat_type_t stattype) 2304 { 2305 return (dladm_stat_table[stattype].ds_querystat(dh, linkid)); 2306 } 2307 2308 dladm_stat_chain_t * 2309 dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2, 2310 dladm_stat_type_t stattype) 2311 { 2312 dladm_stat_chain_t *op1_curr, *op2_curr; 2313 dladm_stat_chain_t *diff_curr; 2314 dladm_stat_chain_t *diff_prev = NULL, *diff_head = NULL; 2315 2316 /* Perform op1 - op2, store result in diff */ 2317 for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) { 2318 for (op2_curr = op2; op2_curr != NULL; 2319 op2_curr = op2_curr->dc_next) { 2320 if (dlstat_match_stats(op1_curr->dc_statentry, 2321 op2_curr->dc_statentry, stattype)) { 2322 break; 2323 } 2324 } 2325 diff_curr = malloc(sizeof (dladm_stat_chain_t)); 2326 if (diff_curr == NULL) 2327 goto done; 2328 2329 diff_curr->dc_next = NULL; 2330 2331 if (op2_curr == NULL) { 2332 /* prev iteration did not have this stat entry */ 2333 diff_curr->dc_statentry = 2334 dlstat_diff_stats(op1_curr->dc_statentry, 2335 NULL, stattype); 2336 } else { 2337 diff_curr->dc_statentry = 2338 dlstat_diff_stats(op1_curr->dc_statentry, 2339 op2_curr->dc_statentry, stattype); 2340 } 2341 2342 if (diff_curr->dc_statentry == NULL) { 2343 free(diff_curr); 2344 goto done; 2345 } 2346 2347 if (diff_prev == NULL) /* head of the diff stat list */ 2348 diff_head = diff_curr; 2349 else 2350 diff_prev->dc_next = diff_curr; 2351 diff_prev = diff_curr; 2352 } 2353 done: 2354 return (diff_head); 2355 } 2356 2357 void 2358 dladm_link_stat_free(dladm_stat_chain_t *curr) 2359 { 2360 while (curr != NULL) { 2361 dladm_stat_chain_t *tofree = curr; 2362 2363 curr = curr->dc_next; 2364 free(tofree->dc_statentry); 2365 free(tofree); 2366 } 2367 } 2368 2369 /* Query all link stats */ 2370 static name_value_stat_t * 2371 i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size) 2372 { 2373 int i; 2374 name_value_stat_t *head_stat = NULL, *prev_stat = NULL; 2375 name_value_stat_t *curr_stat; 2376 2377 for (i = 0; i < size; i++) { 2378 uint64_t *val = (void *) 2379 ((uchar_t *)stats + stats_list[i].si_offset); 2380 2381 curr_stat = calloc(1, sizeof (name_value_stat_t)); 2382 if (curr_stat == NULL) 2383 break; 2384 2385 (void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name, 2386 sizeof (curr_stat->nv_statname)); 2387 curr_stat->nv_statval = *val; 2388 curr_stat->nv_nextstat = NULL; 2389 2390 if (head_stat == NULL) /* First node */ 2391 head_stat = curr_stat; 2392 else 2393 prev_stat->nv_nextstat = curr_stat; 2394 2395 prev_stat = curr_stat; 2396 } 2397 return (head_stat); 2398 } 2399 2400 void * 2401 build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype) 2402 { 2403 name_value_stat_entry_t *name_value_stat_entry; 2404 dladm_stat_desc_t *stattbl_ptr; 2405 void *statfields; 2406 2407 stattbl_ptr = &dladm_stat_table[stattype]; 2408 2409 /* Allocate memory for query all stat entry */ 2410 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 2411 if (name_value_stat_entry == NULL) 2412 goto done; 2413 2414 /* Header for these stat fields */ 2415 (void) strlcpy(name_value_stat_entry->nve_header, statheader, 2416 sizeof (name_value_stat_entry->nve_header)); 2417 2418 /* Extract stat fields from the statentry */ 2419 statfields = (uchar_t *)statentry + 2420 dladm_stat_table[stattype].ds_offset; 2421 2422 /* Convert curr_stat to <statname, statval> pair */ 2423 name_value_stat_entry->nve_stats = 2424 i_dlstat_convert_stats(statfields, 2425 stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize); 2426 done: 2427 return (name_value_stat_entry); 2428 } 2429 2430 void * 2431 i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype) 2432 { 2433 dladm_stat_chain_t *curr; 2434 dladm_stat_chain_t *nvstat_head = NULL, *nvstat_prev = NULL; 2435 dladm_stat_chain_t *nvstat_curr; 2436 2437 /* 2438 * For every stat in the chain, build header and convert all 2439 * its stat fields 2440 */ 2441 for (curr = stat_head; curr != NULL; curr = curr->dc_next) { 2442 nvstat_curr = malloc(sizeof (dladm_stat_chain_t)); 2443 if (nvstat_curr == NULL) 2444 break; 2445 2446 nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader, 2447 curr->dc_statentry, stattype); 2448 2449 if (nvstat_curr->dc_statentry == NULL) { 2450 free(nvstat_curr); 2451 break; 2452 } 2453 2454 nvstat_curr->dc_next = NULL; 2455 2456 if (nvstat_head == NULL) /* First node */ 2457 nvstat_head = nvstat_curr; 2458 else 2459 nvstat_prev->dc_next = nvstat_curr; 2460 2461 nvstat_prev = nvstat_curr; 2462 } 2463 done: 2464 return (nvstat_head); 2465 } 2466 2467 dladm_stat_chain_t * 2468 dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid, 2469 dladm_stat_type_t stattype) 2470 { 2471 dladm_stat_chain_t *stat_head; 2472 dladm_stat_chain_t *nvstat_head = NULL; 2473 2474 /* Query the requested stat */ 2475 stat_head = dladm_link_stat_query(dh, linkid, stattype); 2476 if (stat_head == NULL) 2477 goto done; 2478 2479 /* 2480 * Convert every statfield in every stat-entry of stat chain to 2481 * <statname, statval> pair 2482 */ 2483 nvstat_head = i_walk_dlstat_chain(stat_head, stattype); 2484 2485 /* Free stat_head */ 2486 dladm_link_stat_free(stat_head); 2487 2488 done: 2489 return (nvstat_head); 2490 } 2491 2492 void 2493 dladm_link_stat_query_all_free(dladm_stat_chain_t *curr) 2494 { 2495 while (curr != NULL) { 2496 dladm_stat_chain_t *tofree = curr; 2497 name_value_stat_entry_t *nv_entry = curr->dc_statentry; 2498 name_value_stat_t *nv_curr = nv_entry->nve_stats; 2499 2500 while (nv_curr != NULL) { 2501 name_value_stat_t *nv_tofree = nv_curr; 2502 2503 nv_curr = nv_curr->nv_nextstat; 2504 free(nv_tofree); 2505 } 2506 2507 curr = curr->dc_next; 2508 free(nv_entry); 2509 free(tofree); 2510 } 2511 } 2512 2513 /* flow stats specific routines */ 2514 flow_stat_t * 2515 dladm_flow_stat_query(dladm_handle_t handle, const char *flowname) 2516 { 2517 kstat_t *ksp; 2518 flow_stat_t *flow_stat = NULL; 2519 2520 if (dladm_dld_kcp(handle) == NULL) 2521 return (NULL); 2522 2523 flow_stat = calloc(1, sizeof (flow_stat_t)); 2524 if (flow_stat == NULL) 2525 goto done; 2526 2527 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), NULL, -1, flowname, 2528 "flow"); 2529 2530 if (ksp != NULL) { 2531 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, flow_stat, 2532 flow_stats_list, FLOW_STAT_SIZE); 2533 } 2534 2535 done: 2536 return (flow_stat); 2537 } 2538 2539 flow_stat_t * 2540 dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2) 2541 { 2542 flow_stat_t *diff_stat; 2543 2544 diff_stat = calloc(1, sizeof (flow_stat_t)); 2545 if (diff_stat == NULL) 2546 goto done; 2547 2548 if (op2 == NULL) { 2549 bcopy(op1, diff_stat, sizeof (flow_stat_t)); 2550 } else { 2551 i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list, 2552 FLOW_STAT_SIZE); 2553 } 2554 done: 2555 return (diff_stat); 2556 } 2557 2558 void 2559 dladm_flow_stat_free(flow_stat_t *curr) 2560 { 2561 free(curr); 2562 } 2563 2564 /* Query all flow stats */ 2565 name_value_stat_entry_t * 2566 dladm_flow_stat_query_all(dladm_handle_t handle, const char *flowname) 2567 { 2568 flow_stat_t *flow_stat; 2569 name_value_stat_entry_t *name_value_stat_entry = NULL; 2570 2571 /* Query flow stats */ 2572 flow_stat = dladm_flow_stat_query(handle, flowname); 2573 if (flow_stat == NULL) 2574 goto done; 2575 2576 /* Allocate memory for query all stat entry */ 2577 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 2578 if (name_value_stat_entry == NULL) { 2579 dladm_flow_stat_free(flow_stat); 2580 goto done; 2581 } 2582 2583 /* Header for these stat fields */ 2584 (void) strncpy(name_value_stat_entry->nve_header, flowname, 2585 MAXFLOWNAMELEN); 2586 2587 /* Convert every statfield in flow_stat to <statname, statval> pair */ 2588 name_value_stat_entry->nve_stats = 2589 i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE); 2590 2591 /* Free flow_stat */ 2592 dladm_flow_stat_free(flow_stat); 2593 2594 done: 2595 return (name_value_stat_entry); 2596 } 2597 2598 void 2599 dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr) 2600 { 2601 name_value_stat_t *nv_curr = curr->nve_stats; 2602 2603 while (nv_curr != NULL) { 2604 name_value_stat_t *nv_tofree = nv_curr; 2605 2606 nv_curr = nv_curr->nv_nextstat; 2607 free(nv_tofree); 2608 } 2609 }