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