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