1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2017 Intel Corporation 3 */ 4 5 #include <ctype.h> 6 #include <stdlib.h> 7 8 #include <rte_kvargs.h> 9 #include <rte_telemetry.h> 10 11 #include "rte_ethdev.h" 12 #include "ethdev_driver.h" 13 #include "sff_telemetry.h" 14 15 static const struct { 16 uint32_t capa; 17 const char *name; 18 } rte_eth_fec_capa_name[] = { 19 { RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC), "off" }, 20 { RTE_ETH_FEC_MODE_CAPA_MASK(AUTO), "auto" }, 21 { RTE_ETH_FEC_MODE_CAPA_MASK(BASER), "baser" }, 22 { RTE_ETH_FEC_MODE_CAPA_MASK(RS), "rs" }, 23 { RTE_ETH_FEC_MODE_CAPA_MASK(LLRS), "llrs" }, 24 }; 25 26 static int 27 eth_dev_parse_port_params(const char *params, uint16_t *port_id, 28 char **end_param, bool has_next) 29 { 30 uint64_t pi; 31 32 if (params == NULL || strlen(params) == 0 || 33 !isdigit(*params) || port_id == NULL) 34 return -EINVAL; 35 36 pi = strtoul(params, end_param, 0); 37 if (**end_param != '\0' && !has_next) 38 RTE_ETHDEV_LOG(NOTICE, 39 "Extra parameters passed to ethdev telemetry command, ignoring\n"); 40 41 if (pi >= UINT16_MAX || !rte_eth_dev_is_valid_port(pi)) 42 return -EINVAL; 43 44 *port_id = (uint16_t)pi; 45 46 return 0; 47 } 48 49 static int 50 eth_dev_handle_port_list(const char *cmd __rte_unused, 51 const char *params __rte_unused, 52 struct rte_tel_data *d) 53 { 54 int port_id; 55 56 rte_tel_data_start_array(d, RTE_TEL_INT_VAL); 57 RTE_ETH_FOREACH_DEV(port_id) 58 rte_tel_data_add_array_int(d, port_id); 59 return 0; 60 } 61 62 static void 63 eth_dev_add_port_queue_stats(struct rte_tel_data *d, uint64_t *q_stats, 64 const char *stat_name) 65 { 66 int q; 67 struct rte_tel_data *q_data = rte_tel_data_alloc(); 68 if (q_data == NULL) 69 return; 70 rte_tel_data_start_array(q_data, RTE_TEL_UINT_VAL); 71 for (q = 0; q < RTE_ETHDEV_QUEUE_STAT_CNTRS; q++) 72 rte_tel_data_add_array_uint(q_data, q_stats[q]); 73 rte_tel_data_add_dict_container(d, stat_name, q_data, 0); 74 } 75 76 static int 77 eth_dev_parse_hide_zero(const char *key, const char *value, void *extra_args) 78 { 79 RTE_SET_USED(key); 80 81 if (value == NULL) 82 return -1; 83 84 if (strcmp(value, "true") == 0) 85 *(bool *)extra_args = true; 86 else if (strcmp(value, "false") == 0) 87 *(bool *)extra_args = false; 88 else 89 return -1; 90 91 return 0; 92 } 93 94 #define ADD_DICT_STAT(stats, s) rte_tel_data_add_dict_uint(d, #s, stats.s) 95 96 static int 97 eth_dev_handle_port_stats(const char *cmd __rte_unused, 98 const char *params, 99 struct rte_tel_data *d) 100 { 101 struct rte_eth_stats stats; 102 uint16_t port_id; 103 char *end_param; 104 int ret; 105 106 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 107 if (ret < 0) 108 return ret; 109 110 ret = rte_eth_stats_get(port_id, &stats); 111 if (ret < 0) 112 return -1; 113 114 rte_tel_data_start_dict(d); 115 ADD_DICT_STAT(stats, ipackets); 116 ADD_DICT_STAT(stats, opackets); 117 ADD_DICT_STAT(stats, ibytes); 118 ADD_DICT_STAT(stats, obytes); 119 ADD_DICT_STAT(stats, imissed); 120 ADD_DICT_STAT(stats, ierrors); 121 ADD_DICT_STAT(stats, oerrors); 122 ADD_DICT_STAT(stats, rx_nombuf); 123 eth_dev_add_port_queue_stats(d, stats.q_ipackets, "q_ipackets"); 124 eth_dev_add_port_queue_stats(d, stats.q_opackets, "q_opackets"); 125 eth_dev_add_port_queue_stats(d, stats.q_ibytes, "q_ibytes"); 126 eth_dev_add_port_queue_stats(d, stats.q_obytes, "q_obytes"); 127 eth_dev_add_port_queue_stats(d, stats.q_errors, "q_errors"); 128 129 return 0; 130 } 131 132 static int 133 eth_dev_handle_port_xstats(const char *cmd __rte_unused, 134 const char *params, 135 struct rte_tel_data *d) 136 { 137 const char *const valid_keys[] = { "hide_zero", NULL }; 138 struct rte_eth_xstat *eth_xstats; 139 struct rte_eth_xstat_name *xstat_names; 140 struct rte_kvargs *kvlist; 141 bool hide_zero = false; 142 uint16_t port_id; 143 char *end_param; 144 int num_xstats; 145 int i, ret; 146 147 ret = eth_dev_parse_port_params(params, &port_id, &end_param, true); 148 if (ret < 0) 149 return ret; 150 151 if (*end_param != '\0') { 152 kvlist = rte_kvargs_parse(end_param, valid_keys); 153 ret = rte_kvargs_process(kvlist, NULL, eth_dev_parse_hide_zero, &hide_zero); 154 if (kvlist == NULL || ret != 0) 155 RTE_ETHDEV_LOG(NOTICE, 156 "Unknown extra parameters passed to ethdev telemetry command, ignoring\n"); 157 rte_kvargs_free(kvlist); 158 } 159 160 num_xstats = rte_eth_xstats_get(port_id, NULL, 0); 161 if (num_xstats < 0) 162 return -1; 163 164 /* use one malloc for both names and stats */ 165 eth_xstats = malloc((sizeof(struct rte_eth_xstat) + 166 sizeof(struct rte_eth_xstat_name)) * num_xstats); 167 if (eth_xstats == NULL) 168 return -1; 169 xstat_names = (void *)ð_xstats[num_xstats]; 170 171 ret = rte_eth_xstats_get_names(port_id, xstat_names, num_xstats); 172 if (ret < 0 || ret > num_xstats) { 173 free(eth_xstats); 174 return -1; 175 } 176 177 ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats); 178 if (ret < 0 || ret > num_xstats) { 179 free(eth_xstats); 180 return -1; 181 } 182 183 rte_tel_data_start_dict(d); 184 for (i = 0; i < num_xstats; i++) { 185 if (hide_zero && eth_xstats[i].value == 0) 186 continue; 187 rte_tel_data_add_dict_uint(d, xstat_names[i].name, 188 eth_xstats[i].value); 189 } 190 free(eth_xstats); 191 return 0; 192 } 193 194 #ifndef RTE_EXEC_ENV_WINDOWS 195 static int 196 eth_dev_handle_port_dump_priv(const char *cmd __rte_unused, 197 const char *params, 198 struct rte_tel_data *d) 199 { 200 char *buf, *end_param; 201 uint16_t port_id; 202 int ret; 203 FILE *f; 204 205 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 206 if (ret < 0) 207 return ret; 208 209 buf = calloc(RTE_TEL_MAX_SINGLE_STRING_LEN, sizeof(char)); 210 if (buf == NULL) 211 return -ENOMEM; 212 213 f = fmemopen(buf, RTE_TEL_MAX_SINGLE_STRING_LEN - 1, "w+"); 214 if (f == NULL) { 215 free(buf); 216 return -EINVAL; 217 } 218 219 ret = rte_eth_dev_priv_dump(port_id, f); 220 fclose(f); 221 if (ret == 0) { 222 rte_tel_data_start_dict(d); 223 rte_tel_data_string(d, buf); 224 } 225 226 free(buf); 227 return 0; 228 } 229 #endif /* !RTE_EXEC_ENV_WINDOWS */ 230 231 static int 232 eth_dev_handle_port_link_status(const char *cmd __rte_unused, 233 const char *params, 234 struct rte_tel_data *d) 235 { 236 static const char *status_str = "status"; 237 struct rte_eth_link link; 238 uint16_t port_id; 239 char *end_param; 240 int ret; 241 242 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 243 if (ret < 0) 244 return ret; 245 246 ret = rte_eth_link_get_nowait(port_id, &link); 247 if (ret < 0) 248 return -1; 249 250 rte_tel_data_start_dict(d); 251 if (!link.link_status) { 252 rte_tel_data_add_dict_string(d, status_str, "DOWN"); 253 return 0; 254 } 255 rte_tel_data_add_dict_string(d, status_str, "UP"); 256 rte_tel_data_add_dict_uint(d, "speed", link.link_speed); 257 rte_tel_data_add_dict_string(d, "duplex", 258 (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ? 259 "full-duplex" : "half-duplex"); 260 return 0; 261 } 262 263 static void 264 eth_dev_parse_rx_offloads(uint64_t offload, struct rte_tel_data *d) 265 { 266 uint64_t i; 267 268 rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 269 for (i = 0; i < CHAR_BIT * sizeof(offload); i++) { 270 if ((offload & RTE_BIT64(i)) != 0) 271 rte_tel_data_add_array_string(d, 272 rte_eth_dev_rx_offload_name(offload & RTE_BIT64(i))); 273 } 274 } 275 276 static void 277 eth_dev_parse_tx_offloads(uint64_t offload, struct rte_tel_data *d) 278 { 279 uint64_t i; 280 281 rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 282 for (i = 0; i < CHAR_BIT * sizeof(offload); i++) { 283 if ((offload & RTE_BIT64(i)) != 0) 284 rte_tel_data_add_array_string(d, 285 rte_eth_dev_tx_offload_name(offload & RTE_BIT64(i))); 286 } 287 } 288 289 static int 290 eth_dev_handle_port_info(const char *cmd __rte_unused, 291 const char *params, 292 struct rte_tel_data *d) 293 { 294 struct rte_tel_data *rx_offload, *tx_offload; 295 struct rte_tel_data *rxq_state, *txq_state; 296 char fw_version[RTE_TEL_MAX_STRING_LEN]; 297 char mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; 298 struct rte_eth_dev *eth_dev; 299 uint16_t port_id; 300 char *end_param; 301 int ret; 302 int i; 303 304 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 305 if (ret < 0) 306 return ret; 307 308 eth_dev = &rte_eth_devices[port_id]; 309 310 rxq_state = rte_tel_data_alloc(); 311 if (rxq_state == NULL) 312 return -ENOMEM; 313 314 txq_state = rte_tel_data_alloc(); 315 if (txq_state == NULL) 316 goto free_rxq_state; 317 318 rx_offload = rte_tel_data_alloc(); 319 if (rx_offload == NULL) 320 goto free_txq_state; 321 322 tx_offload = rte_tel_data_alloc(); 323 if (tx_offload == NULL) 324 goto free_rx_offload; 325 326 rte_tel_data_start_dict(d); 327 rte_tel_data_add_dict_string(d, "name", eth_dev->data->name); 328 329 if (rte_eth_dev_fw_version_get(port_id, fw_version, 330 RTE_TEL_MAX_STRING_LEN) == 0) 331 rte_tel_data_add_dict_string(d, "fw_version", fw_version); 332 333 rte_tel_data_add_dict_int(d, "state", eth_dev->state); 334 rte_tel_data_add_dict_int(d, "nb_rx_queues", 335 eth_dev->data->nb_rx_queues); 336 rte_tel_data_add_dict_int(d, "nb_tx_queues", 337 eth_dev->data->nb_tx_queues); 338 rte_tel_data_add_dict_int(d, "port_id", eth_dev->data->port_id); 339 rte_tel_data_add_dict_int(d, "mtu", eth_dev->data->mtu); 340 rte_tel_data_add_dict_uint(d, "rx_mbuf_size_min", 341 eth_dev->data->min_rx_buf_size); 342 rte_ether_format_addr(mac_addr, sizeof(mac_addr), 343 eth_dev->data->mac_addrs); 344 rte_tel_data_add_dict_string(d, "mac_addr", mac_addr); 345 rte_tel_data_add_dict_int(d, "promiscuous", 346 eth_dev->data->promiscuous); 347 rte_tel_data_add_dict_int(d, "scattered_rx", 348 eth_dev->data->scattered_rx); 349 rte_tel_data_add_dict_int(d, "all_multicast", 350 eth_dev->data->all_multicast); 351 rte_tel_data_add_dict_int(d, "dev_started", eth_dev->data->dev_started); 352 rte_tel_data_add_dict_int(d, "lro", eth_dev->data->lro); 353 rte_tel_data_add_dict_int(d, "dev_configured", 354 eth_dev->data->dev_configured); 355 356 rte_tel_data_start_array(rxq_state, RTE_TEL_INT_VAL); 357 for (i = 0; i < eth_dev->data->nb_rx_queues; i++) 358 rte_tel_data_add_array_int(rxq_state, 359 eth_dev->data->rx_queue_state[i]); 360 361 rte_tel_data_start_array(txq_state, RTE_TEL_INT_VAL); 362 for (i = 0; i < eth_dev->data->nb_tx_queues; i++) 363 rte_tel_data_add_array_int(txq_state, 364 eth_dev->data->tx_queue_state[i]); 365 366 rte_tel_data_add_dict_container(d, "rxq_state", rxq_state, 0); 367 rte_tel_data_add_dict_container(d, "txq_state", txq_state, 0); 368 rte_tel_data_add_dict_int(d, "numa_node", eth_dev->data->numa_node); 369 rte_tel_data_add_dict_uint_hex(d, "dev_flags", 370 eth_dev->data->dev_flags, 0); 371 372 eth_dev_parse_rx_offloads(eth_dev->data->dev_conf.rxmode.offloads, 373 rx_offload); 374 rte_tel_data_add_dict_container(d, "rx_offloads", rx_offload, 0); 375 eth_dev_parse_tx_offloads(eth_dev->data->dev_conf.txmode.offloads, 376 tx_offload); 377 rte_tel_data_add_dict_container(d, "tx_offloads", tx_offload, 0); 378 379 rte_tel_data_add_dict_uint_hex(d, "ethdev_rss_hf", 380 eth_dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf, 0); 381 382 return 0; 383 384 free_rx_offload: 385 rte_tel_data_free(rx_offload); 386 free_txq_state: 387 rte_tel_data_free(txq_state); 388 free_rxq_state: 389 rte_tel_data_free(rxq_state); 390 391 return -ENOMEM; 392 } 393 394 static int 395 eth_dev_handle_port_macs(const char *cmd __rte_unused, 396 const char *params, 397 struct rte_tel_data *d) 398 { 399 char mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; 400 struct rte_eth_dev_info dev_info; 401 struct rte_eth_dev *eth_dev; 402 uint16_t port_id; 403 char *end_param; 404 uint32_t i; 405 int ret; 406 407 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 408 if (ret < 0) 409 return ret; 410 411 ret = rte_eth_dev_info_get(port_id, &dev_info); 412 if (ret != 0) 413 return ret; 414 415 eth_dev = &rte_eth_devices[port_id]; 416 rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 417 for (i = 0; i < dev_info.max_mac_addrs; i++) { 418 if (rte_is_zero_ether_addr(ð_dev->data->mac_addrs[i])) 419 continue; 420 421 rte_ether_format_addr(mac_addr, sizeof(mac_addr), 422 ð_dev->data->mac_addrs[i]); 423 rte_tel_data_add_array_string(d, mac_addr); 424 } 425 426 return 0; 427 } 428 429 static int 430 eth_dev_handle_port_flow_ctrl(const char *cmd __rte_unused, 431 const char *params, 432 struct rte_tel_data *d) 433 { 434 struct rte_eth_fc_conf fc_conf; 435 uint16_t port_id; 436 char *end_param; 437 bool rx_fc_en; 438 bool tx_fc_en; 439 int ret; 440 441 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 442 if (ret < 0) 443 return ret; 444 445 ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf); 446 if (ret != 0) { 447 RTE_ETHDEV_LOG(ERR, 448 "Failed to get flow ctrl info, ret = %d\n", ret); 449 return ret; 450 } 451 452 rx_fc_en = fc_conf.mode == RTE_ETH_FC_RX_PAUSE || 453 fc_conf.mode == RTE_ETH_FC_FULL; 454 tx_fc_en = fc_conf.mode == RTE_ETH_FC_TX_PAUSE || 455 fc_conf.mode == RTE_ETH_FC_FULL; 456 457 rte_tel_data_start_dict(d); 458 rte_tel_data_add_dict_uint_hex(d, "high_waterline", fc_conf.high_water, 0); 459 rte_tel_data_add_dict_uint_hex(d, "low_waterline", fc_conf.low_water, 0); 460 rte_tel_data_add_dict_uint_hex(d, "pause_time", fc_conf.pause_time, 0); 461 rte_tel_data_add_dict_string(d, "send_xon", fc_conf.send_xon ? "on" : "off"); 462 rte_tel_data_add_dict_string(d, "mac_ctrl_frame_fwd", 463 fc_conf.mac_ctrl_frame_fwd ? "on" : "off"); 464 rte_tel_data_add_dict_string(d, "rx_pause", rx_fc_en ? "on" : "off"); 465 rte_tel_data_add_dict_string(d, "tx_pause", tx_fc_en ? "on" : "off"); 466 rte_tel_data_add_dict_string(d, "autoneg", fc_conf.autoneg ? "on" : "off"); 467 468 return 0; 469 } 470 471 static int 472 ethdev_parse_queue_params(const char *params, bool is_rx, 473 uint16_t *port_id, uint16_t *queue_id) 474 { 475 struct rte_eth_dev *dev; 476 const char *qid_param; 477 uint16_t nb_queues; 478 char *end_param; 479 uint64_t qid; 480 int ret; 481 482 ret = eth_dev_parse_port_params(params, port_id, &end_param, true); 483 if (ret < 0) 484 return ret; 485 486 dev = &rte_eth_devices[*port_id]; 487 nb_queues = is_rx ? dev->data->nb_rx_queues : dev->data->nb_tx_queues; 488 if (nb_queues == 1 && *end_param == '\0') 489 qid = 0; 490 else { 491 qid_param = strtok(end_param, ","); 492 if (!qid_param || strlen(qid_param) == 0 || !isdigit(*qid_param)) 493 return -EINVAL; 494 495 qid = strtoul(qid_param, &end_param, 0); 496 } 497 if (*end_param != '\0') 498 RTE_ETHDEV_LOG(NOTICE, 499 "Extra parameters passed to ethdev telemetry command, ignoring\n"); 500 501 if (qid >= UINT16_MAX) 502 return -EINVAL; 503 504 *queue_id = qid; 505 return 0; 506 } 507 508 static int 509 eth_dev_add_burst_mode(uint16_t port_id, uint16_t queue_id, 510 bool is_rx, struct rte_tel_data *d) 511 { 512 struct rte_eth_burst_mode mode; 513 int ret; 514 515 if (is_rx) 516 ret = rte_eth_rx_burst_mode_get(port_id, queue_id, &mode); 517 else 518 ret = rte_eth_tx_burst_mode_get(port_id, queue_id, &mode); 519 520 if (ret == -ENOTSUP) 521 return 0; 522 523 if (ret != 0) { 524 RTE_ETHDEV_LOG(ERR, 525 "Failed to get burst mode for port %u\n", port_id); 526 return ret; 527 } 528 529 rte_tel_data_add_dict_uint(d, "burst_flags", mode.flags); 530 rte_tel_data_add_dict_string(d, "burst_mode", mode.info); 531 return 0; 532 } 533 534 static int 535 eth_dev_handle_port_rxq(const char *cmd __rte_unused, 536 const char *params, 537 struct rte_tel_data *d) 538 { 539 struct rte_eth_thresh *rx_thresh; 540 struct rte_eth_rxconf *rxconf; 541 struct rte_eth_rxq_info qinfo; 542 struct rte_tel_data *offload; 543 uint16_t port_id, queue_id; 544 int ret; 545 546 ret = ethdev_parse_queue_params(params, true, &port_id, &queue_id); 547 if (ret != 0) 548 return ret; 549 550 ret = rte_eth_rx_queue_info_get(port_id, queue_id, &qinfo); 551 if (ret != 0) 552 return ret; 553 554 rte_tel_data_start_dict(d); 555 rte_tel_data_add_dict_string(d, "mempool_name", qinfo.mp->name); 556 rte_tel_data_add_dict_uint(d, "socket_id", qinfo.mp->socket_id); 557 558 rx_thresh = &qinfo.conf.rx_thresh; 559 rte_tel_data_add_dict_uint(d, "host_threshold", rx_thresh->hthresh); 560 rte_tel_data_add_dict_uint(d, "prefetch_threshold", rx_thresh->pthresh); 561 rte_tel_data_add_dict_uint(d, "writeback_threshold", rx_thresh->wthresh); 562 563 rxconf = &qinfo.conf; 564 rte_tel_data_add_dict_uint(d, "free_threshold", rxconf->rx_free_thresh); 565 rte_tel_data_add_dict_string(d, "rx_drop_en", 566 rxconf->rx_drop_en == 0 ? "off" : "on"); 567 rte_tel_data_add_dict_string(d, "deferred_start", 568 rxconf->rx_deferred_start == 0 ? "off" : "on"); 569 rte_tel_data_add_dict_uint(d, "rx_nseg", rxconf->rx_nseg); 570 rte_tel_data_add_dict_uint(d, "share_group", rxconf->share_group); 571 rte_tel_data_add_dict_uint(d, "share_qid", rxconf->share_qid); 572 573 offload = rte_tel_data_alloc(); 574 if (offload == NULL) 575 return -ENOMEM; 576 577 eth_dev_parse_rx_offloads(rxconf->offloads, offload); 578 rte_tel_data_add_dict_container(d, "offloads", offload, 0); 579 580 rte_tel_data_add_dict_uint(d, "rx_nmempool", rxconf->rx_nmempool); 581 582 rte_tel_data_add_dict_string(d, "scattered_rx", 583 qinfo.scattered_rx == 0 ? "off" : "on"); 584 rte_tel_data_add_dict_uint(d, "queue_state", qinfo.queue_state); 585 rte_tel_data_add_dict_uint(d, "nb_desc", qinfo.nb_desc); 586 rte_tel_data_add_dict_uint(d, "rx_buf_size", qinfo.rx_buf_size); 587 rte_tel_data_add_dict_uint(d, "avail_thresh", qinfo.avail_thresh); 588 589 ret = eth_dev_add_burst_mode(port_id, queue_id, true, d); 590 if (ret != 0) 591 rte_tel_data_free(offload); 592 593 return ret; 594 } 595 596 static int 597 eth_dev_handle_port_txq(const char *cmd __rte_unused, 598 const char *params, 599 struct rte_tel_data *d) 600 { 601 struct rte_eth_thresh *tx_thresh; 602 struct rte_eth_txconf *txconf; 603 struct rte_eth_txq_info qinfo; 604 struct rte_tel_data *offload; 605 uint16_t port_id, queue_id; 606 int ret; 607 608 ret = ethdev_parse_queue_params(params, false, &port_id, &queue_id); 609 if (ret != 0) 610 return ret; 611 612 ret = rte_eth_tx_queue_info_get(port_id, queue_id, &qinfo); 613 if (ret != 0) 614 return ret; 615 616 rte_tel_data_start_dict(d); 617 tx_thresh = &qinfo.conf.tx_thresh; 618 txconf = &qinfo.conf; 619 rte_tel_data_add_dict_uint(d, "host_threshold", tx_thresh->hthresh); 620 rte_tel_data_add_dict_uint(d, "prefetch_threshold", tx_thresh->pthresh); 621 rte_tel_data_add_dict_uint(d, "writeback_threshold", tx_thresh->wthresh); 622 rte_tel_data_add_dict_uint(d, "rs_threshold", txconf->tx_rs_thresh); 623 rte_tel_data_add_dict_uint(d, "free_threshold", txconf->tx_free_thresh); 624 rte_tel_data_add_dict_string(d, "deferred_start", 625 txconf->tx_deferred_start == 0 ? "off" : "on"); 626 627 offload = rte_tel_data_alloc(); 628 if (offload == NULL) 629 return -ENOMEM; 630 631 eth_dev_parse_tx_offloads(txconf->offloads, offload); 632 rte_tel_data_add_dict_container(d, "offloads", offload, 0); 633 634 rte_tel_data_add_dict_uint(d, "queue_state", qinfo.queue_state); 635 rte_tel_data_add_dict_uint(d, "nb_desc", qinfo.nb_desc); 636 637 ret = eth_dev_add_burst_mode(port_id, queue_id, false, d); 638 if (ret != 0) 639 rte_tel_data_free(offload); 640 641 return 0; 642 } 643 644 static int 645 eth_dev_add_dcb_tc(struct rte_eth_dcb_info *dcb_info, struct rte_tel_data *d) 646 { 647 struct rte_tel_data *tcds[RTE_ETH_DCB_NUM_TCS] = {NULL}; 648 struct rte_eth_dcb_tc_queue_mapping *tcq; 649 char bw_percent[RTE_TEL_MAX_STRING_LEN]; 650 char name[RTE_TEL_MAX_STRING_LEN]; 651 struct rte_tel_data *tcd; 652 uint32_t i; 653 654 for (i = 0; i < dcb_info->nb_tcs; i++) { 655 tcd = rte_tel_data_alloc(); 656 if (tcd == NULL) { 657 while (i-- > 0) 658 rte_tel_data_free(tcds[i]); 659 return -ENOMEM; 660 } 661 662 tcds[i] = tcd; 663 rte_tel_data_start_dict(tcd); 664 665 rte_tel_data_add_dict_uint(tcd, "priority", dcb_info->prio_tc[i]); 666 snprintf(bw_percent, RTE_TEL_MAX_STRING_LEN, 667 "%u%%", dcb_info->tc_bws[i]); 668 rte_tel_data_add_dict_string(tcd, "bw_percent", bw_percent); 669 670 tcq = &dcb_info->tc_queue; 671 rte_tel_data_add_dict_uint(tcd, "rxq_base", tcq->tc_rxq[0][i].base); 672 rte_tel_data_add_dict_uint(tcd, "txq_base", tcq->tc_txq[0][i].base); 673 rte_tel_data_add_dict_uint(tcd, "nb_rxq", tcq->tc_rxq[0][i].nb_queue); 674 rte_tel_data_add_dict_uint(tcd, "nb_txq", tcq->tc_txq[0][i].nb_queue); 675 676 snprintf(name, RTE_TEL_MAX_STRING_LEN, "tc%u", i); 677 rte_tel_data_add_dict_container(d, name, tcd, 0); 678 } 679 680 return 0; 681 } 682 683 static int 684 eth_dev_add_dcb_info(uint16_t port_id, struct rte_tel_data *d) 685 { 686 struct rte_eth_dcb_info dcb_info; 687 int ret; 688 689 ret = rte_eth_dev_get_dcb_info(port_id, &dcb_info); 690 if (ret != 0) { 691 RTE_ETHDEV_LOG(ERR, 692 "Failed to get dcb info, ret = %d\n", ret); 693 return ret; 694 } 695 696 rte_tel_data_start_dict(d); 697 rte_tel_data_add_dict_uint(d, "tc_num", dcb_info.nb_tcs); 698 699 if (dcb_info.nb_tcs > 0) 700 return eth_dev_add_dcb_tc(&dcb_info, d); 701 702 return 0; 703 } 704 705 static int 706 eth_dev_handle_port_dcb(const char *cmd __rte_unused, 707 const char *params, 708 struct rte_tel_data *d) 709 { 710 uint16_t port_id; 711 char *end_param; 712 int ret; 713 714 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 715 if (ret < 0) 716 return ret; 717 718 return eth_dev_add_dcb_info(port_id, d); 719 } 720 721 static int 722 eth_dev_add_rss_info(struct rte_eth_rss_conf *rss_conf, struct rte_tel_data *d) 723 { 724 const uint32_t key_len = rss_conf->rss_key_len * 2 + 1; 725 char *rss_key; 726 char key[3]; /* FF\0 */ 727 uint32_t i; 728 int ret; 729 730 rss_key = malloc(key_len); 731 if (rss_key == NULL) 732 return -ENOMEM; 733 734 rte_tel_data_start_dict(d); 735 rte_tel_data_add_dict_uint_hex(d, "rss_hf", rss_conf->rss_hf, 0); 736 rte_tel_data_add_dict_uint(d, "rss_key_len", rss_conf->rss_key_len); 737 738 memset(rss_key, 0, key_len); 739 for (i = 0; i < rss_conf->rss_key_len; i++) { 740 ret = snprintf(key, 3, "%02x", rss_conf->rss_key[i]); 741 if (ret < 0) 742 goto free_rss_key; 743 strlcat(rss_key, key, key_len); 744 } 745 ret = rte_tel_data_add_dict_string(d, "rss_key", rss_key); 746 747 free_rss_key: 748 free(rss_key); 749 750 return ret; 751 } 752 753 static int 754 eth_dev_handle_port_rss_info(const char *cmd __rte_unused, 755 const char *params, 756 struct rte_tel_data *d) 757 { 758 struct rte_eth_dev_info dev_info; 759 struct rte_eth_rss_conf rss_conf; 760 uint8_t key_len; 761 uint16_t port_id; 762 char *end_param; 763 int ret; 764 765 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 766 if (ret < 0) 767 return ret; 768 769 ret = rte_eth_dev_info_get(port_id, &dev_info); 770 if (ret != 0) { 771 RTE_ETHDEV_LOG(ERR, 772 "Failed to get device info, ret = %d\n", ret); 773 return ret; 774 } 775 776 key_len = dev_info.hash_key_size ? dev_info.hash_key_size : 40; 777 rss_conf.rss_key_len = key_len; 778 rss_conf.rss_key = malloc(key_len); 779 if (rss_conf.rss_key == NULL) 780 return -ENOMEM; 781 782 ret = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf); 783 if (ret != 0) { 784 free(rss_conf.rss_key); 785 return ret; 786 } 787 788 ret = eth_dev_add_rss_info(&rss_conf, d); 789 free(rss_conf.rss_key); 790 return ret; 791 } 792 793 static const char * 794 eth_dev_fec_capa_to_string(uint32_t fec_capa) 795 { 796 uint32_t i; 797 798 for (i = 0; i < RTE_DIM(rte_eth_fec_capa_name); i++) { 799 if ((fec_capa & rte_eth_fec_capa_name[i].capa) != 0) 800 return rte_eth_fec_capa_name[i].name; 801 } 802 803 return "unknown"; 804 } 805 806 static void 807 eth_dev_fec_capas_to_string(uint32_t fec_capa, char *fec_name, uint32_t len) 808 { 809 bool valid = false; 810 size_t count = 0; 811 uint32_t i; 812 813 for (i = 0; i < RTE_DIM(rte_eth_fec_capa_name); i++) { 814 if ((fec_capa & rte_eth_fec_capa_name[i].capa) != 0) { 815 strlcat(fec_name, rte_eth_fec_capa_name[i].name, len); 816 count = strlcat(fec_name, " ", len); 817 valid = true; 818 } 819 } 820 821 if (!valid) 822 count = snprintf(fec_name, len, "unknown "); 823 824 if (count >= len) { 825 RTE_ETHDEV_LOG(WARNING, "FEC capa names may be truncated\n"); 826 count = len; 827 } 828 829 fec_name[count - 1] = '\0'; 830 } 831 832 static int 833 eth_dev_get_fec_capability(uint16_t port_id, struct rte_tel_data *d) 834 { 835 struct rte_eth_fec_capa *speed_fec_capa; 836 char fec_name[RTE_TEL_MAX_STRING_LEN]; 837 char speed[RTE_TEL_MAX_STRING_LEN]; 838 uint32_t capa_num; 839 uint32_t i, j; 840 int ret; 841 842 ret = rte_eth_fec_get_capability(port_id, NULL, 0); 843 if (ret <= 0) 844 return ret == 0 ? -EINVAL : ret; 845 846 capa_num = ret; 847 speed_fec_capa = calloc(capa_num, sizeof(struct rte_eth_fec_capa)); 848 if (speed_fec_capa == NULL) 849 return -ENOMEM; 850 851 ret = rte_eth_fec_get_capability(port_id, speed_fec_capa, capa_num); 852 if (ret <= 0) { 853 ret = ret == 0 ? -EINVAL : ret; 854 goto out; 855 } 856 857 for (i = 0; i < capa_num; i++) { 858 memset(fec_name, 0, RTE_TEL_MAX_STRING_LEN); 859 eth_dev_fec_capas_to_string(speed_fec_capa[i].capa, fec_name, 860 RTE_TEL_MAX_STRING_LEN); 861 862 memset(speed, 0, RTE_TEL_MAX_STRING_LEN); 863 ret = snprintf(speed, RTE_TEL_MAX_STRING_LEN, "%s", 864 rte_eth_link_speed_to_str(speed_fec_capa[i].speed)); 865 if (ret < 0) 866 goto out; 867 868 for (j = 0; j < strlen(speed); j++) { 869 if (speed[j] == ' ') 870 speed[j] = '_'; 871 } 872 873 rte_tel_data_add_dict_string(d, speed, fec_name); 874 } 875 876 out: 877 free(speed_fec_capa); 878 return ret > 0 ? 0 : ret; 879 } 880 881 static int 882 eth_dev_handle_port_fec(const char *cmd __rte_unused, 883 const char *params, 884 struct rte_tel_data *d) 885 { 886 struct rte_tel_data *fec_capas; 887 uint32_t fec_mode; 888 uint16_t port_id; 889 char *end_param; 890 int ret; 891 892 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 893 if (ret < 0) 894 return ret; 895 896 ret = rte_eth_fec_get(port_id, &fec_mode); 897 if (ret != 0) 898 return ret; 899 900 rte_tel_data_start_dict(d); 901 rte_tel_data_add_dict_string(d, "fec_mode", 902 eth_dev_fec_capa_to_string(fec_mode)); 903 904 fec_capas = rte_tel_data_alloc(); 905 if (fec_capas == NULL) 906 return -ENOMEM; 907 908 rte_tel_data_start_dict(fec_capas); 909 ret = eth_dev_get_fec_capability(port_id, fec_capas); 910 if (ret != 0) { 911 rte_tel_data_free(fec_capas); 912 return ret; 913 } 914 915 rte_tel_data_add_dict_container(d, "fec_capability", fec_capas, 0); 916 return 0; 917 } 918 919 static int 920 eth_dev_add_vlan_id(int port_id, struct rte_tel_data *d) 921 { 922 struct rte_tel_data *vlan_blks[64] = {NULL}; 923 uint16_t vlan_num, vidx, vbit, num_blks; 924 char blk_name[RTE_TEL_MAX_STRING_LEN]; 925 struct rte_vlan_filter_conf *vfc; 926 struct rte_tel_data *vlan_blk; 927 struct rte_tel_data *vd; 928 uint64_t bit_width; 929 uint64_t vlan_id; 930 931 vd = rte_tel_data_alloc(); 932 if (vd == NULL) 933 return -ENOMEM; 934 935 vfc = &rte_eth_devices[port_id].data->vlan_filter_conf; 936 bit_width = CHAR_BIT * sizeof(uint64_t); 937 vlan_num = 0; 938 num_blks = 0; 939 940 rte_tel_data_start_dict(vd); 941 for (vidx = 0; vidx < RTE_DIM(vfc->ids); vidx++) { 942 if (vfc->ids[vidx] == 0) 943 continue; 944 945 vlan_blk = rte_tel_data_alloc(); 946 if (vlan_blk == NULL) 947 goto free_all; 948 949 vlan_blks[num_blks] = vlan_blk; 950 num_blks++; 951 snprintf(blk_name, RTE_TEL_MAX_STRING_LEN, "vlan_%"PRIu64"_to_%"PRIu64"", 952 bit_width * vidx, bit_width * (vidx + 1) - 1); 953 rte_tel_data_start_array(vlan_blk, RTE_TEL_UINT_VAL); 954 rte_tel_data_add_dict_container(vd, blk_name, vlan_blk, 0); 955 956 for (vbit = 0; vbit < bit_width; vbit++) { 957 if ((vfc->ids[vidx] & RTE_BIT64(vbit)) == 0) 958 continue; 959 960 vlan_id = bit_width * vidx + vbit; 961 rte_tel_data_add_array_uint(vlan_blk, vlan_id); 962 vlan_num++; 963 } 964 } 965 966 rte_tel_data_add_dict_uint(d, "vlan_num", vlan_num); 967 rte_tel_data_add_dict_container(d, "vlan_ids", vd, 0); 968 969 return 0; 970 971 free_all: 972 while (num_blks-- > 0) 973 rte_tel_data_free(vlan_blks[num_blks]); 974 975 rte_tel_data_free(vd); 976 return -ENOMEM; 977 } 978 979 static int 980 eth_dev_handle_port_vlan(const char *cmd __rte_unused, 981 const char *params, 982 struct rte_tel_data *d) 983 { 984 struct rte_eth_txmode *txmode; 985 struct rte_eth_conf dev_conf; 986 uint16_t port_id; 987 int offload, ret; 988 char *end_param; 989 990 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 991 if (ret < 0) 992 return ret; 993 994 ret = rte_eth_dev_conf_get(port_id, &dev_conf); 995 if (ret != 0) { 996 RTE_ETHDEV_LOG(ERR, 997 "Failed to get device configuration, ret = %d\n", ret); 998 return ret; 999 } 1000 1001 txmode = &dev_conf.txmode; 1002 rte_tel_data_start_dict(d); 1003 rte_tel_data_add_dict_uint(d, "pvid", txmode->pvid); 1004 rte_tel_data_add_dict_uint(d, "hw_vlan_reject_tagged", 1005 txmode->hw_vlan_reject_tagged); 1006 rte_tel_data_add_dict_uint(d, "hw_vlan_reject_untagged", 1007 txmode->hw_vlan_reject_untagged); 1008 rte_tel_data_add_dict_uint(d, "hw_vlan_insert_pvid", 1009 txmode->hw_vlan_insert_pvid); 1010 1011 offload = rte_eth_dev_get_vlan_offload(port_id); 1012 rte_tel_data_add_dict_string(d, "VLAN_STRIP", 1013 ((offload & RTE_ETH_VLAN_STRIP_OFFLOAD) != 0) ? "on" : "off"); 1014 rte_tel_data_add_dict_string(d, "VLAN_EXTEND", 1015 ((offload & RTE_ETH_VLAN_EXTEND_OFFLOAD) != 0) ? "on" : "off"); 1016 rte_tel_data_add_dict_string(d, "QINQ_STRIP", 1017 ((offload & RTE_ETH_QINQ_STRIP_OFFLOAD) != 0) ? "on" : "off"); 1018 rte_tel_data_add_dict_string(d, "VLAN_FILTER", 1019 ((offload & RTE_ETH_VLAN_FILTER_OFFLOAD) != 0) ? "on" : "off"); 1020 1021 return eth_dev_add_vlan_id(port_id, d); 1022 } 1023 1024 RTE_INIT(ethdev_init_telemetry) 1025 { 1026 rte_telemetry_register_cmd("/ethdev/list", eth_dev_handle_port_list, 1027 "Returns list of available ethdev ports. Takes no parameters"); 1028 rte_telemetry_register_cmd("/ethdev/stats", eth_dev_handle_port_stats, 1029 "Returns the common stats for a port. Parameters: int port_id"); 1030 rte_telemetry_register_cmd("/ethdev/xstats", eth_dev_handle_port_xstats, 1031 "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); 1032 #ifndef RTE_EXEC_ENV_WINDOWS 1033 rte_telemetry_register_cmd("/ethdev/dump_priv", eth_dev_handle_port_dump_priv, 1034 "Returns dump private information for a port. Parameters: int port_id"); 1035 #endif 1036 rte_telemetry_register_cmd("/ethdev/link_status", 1037 eth_dev_handle_port_link_status, 1038 "Returns the link status for a port. Parameters: int port_id"); 1039 rte_telemetry_register_cmd("/ethdev/info", eth_dev_handle_port_info, 1040 "Returns the device info for a port. Parameters: int port_id"); 1041 rte_telemetry_register_cmd("/ethdev/module_eeprom", eth_dev_handle_port_module_eeprom, 1042 "Returns module EEPROM info with SFF specs. Parameters: int port_id"); 1043 rte_telemetry_register_cmd("/ethdev/macs", eth_dev_handle_port_macs, 1044 "Returns the MAC addresses for a port. Parameters: int port_id"); 1045 rte_telemetry_register_cmd("/ethdev/flow_ctrl", eth_dev_handle_port_flow_ctrl, 1046 "Returns flow ctrl info for a port. Parameters: int port_id"); 1047 rte_telemetry_register_cmd("/ethdev/rx_queue", eth_dev_handle_port_rxq, 1048 "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); 1049 rte_telemetry_register_cmd("/ethdev/tx_queue", eth_dev_handle_port_txq, 1050 "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); 1051 rte_telemetry_register_cmd("/ethdev/dcb", eth_dev_handle_port_dcb, 1052 "Returns DCB info for a port. Parameters: int port_id"); 1053 rte_telemetry_register_cmd("/ethdev/rss_info", eth_dev_handle_port_rss_info, 1054 "Returns RSS info for a port. Parameters: int port_id"); 1055 rte_telemetry_register_cmd("/ethdev/fec", eth_dev_handle_port_fec, 1056 "Returns FEC info for a port. Parameters: int port_id"); 1057 rte_telemetry_register_cmd("/ethdev/vlan", eth_dev_handle_port_vlan, 1058 "Returns VLAN info for a port. Parameters: int port_id"); 1059 } 1060