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 #include "rte_tm.h" 15 16 static const struct { 17 uint32_t capa; 18 const char *name; 19 } rte_eth_fec_capa_name[] = { 20 { RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC), "off" }, 21 { RTE_ETH_FEC_MODE_CAPA_MASK(AUTO), "auto" }, 22 { RTE_ETH_FEC_MODE_CAPA_MASK(BASER), "baser" }, 23 { RTE_ETH_FEC_MODE_CAPA_MASK(RS), "rs" }, 24 { RTE_ETH_FEC_MODE_CAPA_MASK(LLRS), "llrs" }, 25 }; 26 27 static int 28 eth_dev_parse_port_params(const char *params, uint16_t *port_id, 29 char **end_param, bool has_next) 30 { 31 uint64_t pi; 32 33 if (params == NULL || strlen(params) == 0 || 34 !isdigit(*params) || port_id == NULL) 35 return -EINVAL; 36 37 pi = strtoul(params, end_param, 0); 38 if (**end_param != '\0' && !has_next) 39 RTE_ETHDEV_LOG_LINE(NOTICE, 40 "Extra parameters passed to ethdev telemetry command, ignoring"); 41 42 if (pi >= UINT16_MAX || !rte_eth_dev_is_valid_port(pi)) 43 return -EINVAL; 44 45 *port_id = (uint16_t)pi; 46 47 return 0; 48 } 49 50 static int 51 eth_dev_handle_port_list(const char *cmd __rte_unused, 52 const char *params __rte_unused, 53 struct rte_tel_data *d) 54 { 55 int port_id; 56 57 rte_tel_data_start_array(d, RTE_TEL_INT_VAL); 58 RTE_ETH_FOREACH_DEV(port_id) 59 rte_tel_data_add_array_int(d, port_id); 60 return 0; 61 } 62 63 static void 64 eth_dev_add_port_queue_stats(struct rte_tel_data *d, uint64_t *q_stats, 65 const char *stat_name) 66 { 67 int q; 68 struct rte_tel_data *q_data = rte_tel_data_alloc(); 69 if (q_data == NULL) 70 return; 71 rte_tel_data_start_array(q_data, RTE_TEL_UINT_VAL); 72 for (q = 0; q < RTE_ETHDEV_QUEUE_STAT_CNTRS; q++) 73 rte_tel_data_add_array_uint(q_data, q_stats[q]); 74 rte_tel_data_add_dict_container(d, stat_name, q_data, 0); 75 } 76 77 static int 78 eth_dev_parse_hide_zero(const char *key, const char *value, void *extra_args) 79 { 80 RTE_SET_USED(key); 81 82 if (value == NULL) 83 return -1; 84 85 if (strcmp(value, "true") == 0) 86 *(bool *)extra_args = true; 87 else if (strcmp(value, "false") == 0) 88 *(bool *)extra_args = false; 89 else 90 return -1; 91 92 return 0; 93 } 94 95 #define ADD_DICT_STAT(stats, s) rte_tel_data_add_dict_uint(d, #s, stats.s) 96 97 static int 98 eth_dev_handle_port_stats(const char *cmd __rte_unused, 99 const char *params, 100 struct rte_tel_data *d) 101 { 102 struct rte_eth_stats stats; 103 uint16_t port_id; 104 char *end_param; 105 int ret; 106 107 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 108 if (ret < 0) 109 return ret; 110 111 ret = rte_eth_stats_get(port_id, &stats); 112 if (ret < 0) 113 return -1; 114 115 rte_tel_data_start_dict(d); 116 ADD_DICT_STAT(stats, ipackets); 117 ADD_DICT_STAT(stats, opackets); 118 ADD_DICT_STAT(stats, ibytes); 119 ADD_DICT_STAT(stats, obytes); 120 ADD_DICT_STAT(stats, imissed); 121 ADD_DICT_STAT(stats, ierrors); 122 ADD_DICT_STAT(stats, oerrors); 123 ADD_DICT_STAT(stats, rx_nombuf); 124 eth_dev_add_port_queue_stats(d, stats.q_ipackets, "q_ipackets"); 125 eth_dev_add_port_queue_stats(d, stats.q_opackets, "q_opackets"); 126 eth_dev_add_port_queue_stats(d, stats.q_ibytes, "q_ibytes"); 127 eth_dev_add_port_queue_stats(d, stats.q_obytes, "q_obytes"); 128 eth_dev_add_port_queue_stats(d, stats.q_errors, "q_errors"); 129 130 return 0; 131 } 132 133 static int 134 eth_dev_handle_port_xstats(const char *cmd __rte_unused, 135 const char *params, 136 struct rte_tel_data *d) 137 { 138 const char *const valid_keys[] = { "hide_zero", NULL }; 139 struct rte_eth_xstat *eth_xstats; 140 struct rte_eth_xstat_name *xstat_names; 141 struct rte_kvargs *kvlist; 142 bool hide_zero = false; 143 uint16_t port_id; 144 char *end_param; 145 int num_xstats; 146 int i, ret; 147 148 ret = eth_dev_parse_port_params(params, &port_id, &end_param, true); 149 if (ret < 0) 150 return ret; 151 152 if (*end_param != '\0') { 153 kvlist = rte_kvargs_parse(end_param, valid_keys); 154 ret = rte_kvargs_process(kvlist, NULL, eth_dev_parse_hide_zero, &hide_zero); 155 if (kvlist == NULL || ret != 0) 156 RTE_ETHDEV_LOG_LINE(NOTICE, 157 "Unknown extra parameters passed to ethdev telemetry command, ignoring"); 158 rte_kvargs_free(kvlist); 159 } 160 161 num_xstats = rte_eth_xstats_get(port_id, NULL, 0); 162 if (num_xstats < 0) 163 return -1; 164 165 /* use one malloc for both names and stats */ 166 eth_xstats = malloc((sizeof(struct rte_eth_xstat) + 167 sizeof(struct rte_eth_xstat_name)) * num_xstats); 168 if (eth_xstats == NULL) 169 return -1; 170 xstat_names = (void *)ð_xstats[num_xstats]; 171 172 ret = rte_eth_xstats_get_names(port_id, xstat_names, num_xstats); 173 if (ret < 0 || ret > num_xstats) { 174 free(eth_xstats); 175 return -1; 176 } 177 178 ret = rte_eth_xstats_get(port_id, eth_xstats, num_xstats); 179 if (ret < 0 || ret > num_xstats) { 180 free(eth_xstats); 181 return -1; 182 } 183 184 rte_tel_data_start_dict(d); 185 for (i = 0; i < num_xstats; i++) { 186 if (hide_zero && eth_xstats[i].value == 0) 187 continue; 188 rte_tel_data_add_dict_uint(d, xstat_names[i].name, 189 eth_xstats[i].value); 190 } 191 free(eth_xstats); 192 return 0; 193 } 194 195 #ifndef RTE_EXEC_ENV_WINDOWS 196 static int 197 eth_dev_handle_port_dump_priv(const char *cmd __rte_unused, 198 const char *params, 199 struct rte_tel_data *d) 200 { 201 char *buf, *end_param; 202 uint16_t port_id; 203 int ret; 204 FILE *f; 205 206 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 207 if (ret < 0) 208 return ret; 209 210 buf = calloc(RTE_TEL_MAX_SINGLE_STRING_LEN, sizeof(char)); 211 if (buf == NULL) 212 return -ENOMEM; 213 214 f = fmemopen(buf, RTE_TEL_MAX_SINGLE_STRING_LEN - 1, "w+"); 215 if (f == NULL) { 216 free(buf); 217 return -EINVAL; 218 } 219 220 ret = rte_eth_dev_priv_dump(port_id, f); 221 fclose(f); 222 if (ret == 0) { 223 rte_tel_data_start_dict(d); 224 rte_tel_data_string(d, buf); 225 } 226 227 free(buf); 228 return 0; 229 } 230 #endif /* !RTE_EXEC_ENV_WINDOWS */ 231 232 static int 233 eth_dev_handle_port_link_status(const char *cmd __rte_unused, 234 const char *params, 235 struct rte_tel_data *d) 236 { 237 static const char *status_str = "status"; 238 struct rte_eth_link link; 239 uint16_t port_id; 240 char *end_param; 241 int ret; 242 243 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 244 if (ret < 0) 245 return ret; 246 247 ret = rte_eth_link_get_nowait(port_id, &link); 248 if (ret < 0) 249 return -1; 250 251 rte_tel_data_start_dict(d); 252 if (!link.link_status) { 253 rte_tel_data_add_dict_string(d, status_str, "DOWN"); 254 return 0; 255 } 256 rte_tel_data_add_dict_string(d, status_str, "UP"); 257 rte_tel_data_add_dict_uint(d, "speed", link.link_speed); 258 rte_tel_data_add_dict_string(d, "duplex", 259 (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ? 260 "full-duplex" : "half-duplex"); 261 return 0; 262 } 263 264 static void 265 eth_dev_parse_rx_offloads(uint64_t offload, struct rte_tel_data *d) 266 { 267 uint64_t i; 268 269 rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 270 for (i = 0; i < CHAR_BIT * sizeof(offload); i++) { 271 if ((offload & RTE_BIT64(i)) != 0) 272 rte_tel_data_add_array_string(d, 273 rte_eth_dev_rx_offload_name(offload & RTE_BIT64(i))); 274 } 275 } 276 277 static void 278 eth_dev_parse_tx_offloads(uint64_t offload, struct rte_tel_data *d) 279 { 280 uint64_t i; 281 282 rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 283 for (i = 0; i < CHAR_BIT * sizeof(offload); i++) { 284 if ((offload & RTE_BIT64(i)) != 0) 285 rte_tel_data_add_array_string(d, 286 rte_eth_dev_tx_offload_name(offload & RTE_BIT64(i))); 287 } 288 } 289 290 static int 291 eth_dev_handle_port_info(const char *cmd __rte_unused, 292 const char *params, 293 struct rte_tel_data *d) 294 { 295 struct rte_tel_data *rx_offload, *tx_offload; 296 struct rte_tel_data *rxq_state, *txq_state; 297 char fw_version[RTE_TEL_MAX_STRING_LEN]; 298 char mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; 299 struct rte_eth_dev *eth_dev; 300 uint16_t port_id; 301 char *end_param; 302 int ret; 303 int i; 304 305 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 306 if (ret < 0) 307 return ret; 308 309 eth_dev = &rte_eth_devices[port_id]; 310 311 rxq_state = rte_tel_data_alloc(); 312 if (rxq_state == NULL) 313 return -ENOMEM; 314 315 txq_state = rte_tel_data_alloc(); 316 if (txq_state == NULL) 317 goto free_rxq_state; 318 319 rx_offload = rte_tel_data_alloc(); 320 if (rx_offload == NULL) 321 goto free_txq_state; 322 323 tx_offload = rte_tel_data_alloc(); 324 if (tx_offload == NULL) 325 goto free_rx_offload; 326 327 rte_tel_data_start_dict(d); 328 rte_tel_data_add_dict_string(d, "name", eth_dev->data->name); 329 330 if (rte_eth_dev_fw_version_get(port_id, fw_version, 331 RTE_TEL_MAX_STRING_LEN) == 0) 332 rte_tel_data_add_dict_string(d, "fw_version", fw_version); 333 334 rte_tel_data_add_dict_int(d, "state", eth_dev->state); 335 rte_tel_data_add_dict_int(d, "nb_rx_queues", 336 eth_dev->data->nb_rx_queues); 337 rte_tel_data_add_dict_int(d, "nb_tx_queues", 338 eth_dev->data->nb_tx_queues); 339 rte_tel_data_add_dict_int(d, "port_id", eth_dev->data->port_id); 340 rte_tel_data_add_dict_int(d, "mtu", eth_dev->data->mtu); 341 rte_tel_data_add_dict_uint(d, "rx_mbuf_size_min", 342 eth_dev->data->min_rx_buf_size); 343 rte_ether_format_addr(mac_addr, sizeof(mac_addr), 344 eth_dev->data->mac_addrs); 345 rte_tel_data_add_dict_string(d, "mac_addr", mac_addr); 346 rte_tel_data_add_dict_int(d, "promiscuous", 347 eth_dev->data->promiscuous); 348 rte_tel_data_add_dict_int(d, "scattered_rx", 349 eth_dev->data->scattered_rx); 350 rte_tel_data_add_dict_int(d, "all_multicast", 351 eth_dev->data->all_multicast); 352 rte_tel_data_add_dict_int(d, "dev_started", eth_dev->data->dev_started); 353 rte_tel_data_add_dict_int(d, "lro", eth_dev->data->lro); 354 rte_tel_data_add_dict_int(d, "dev_configured", 355 eth_dev->data->dev_configured); 356 357 rte_tel_data_start_array(rxq_state, RTE_TEL_INT_VAL); 358 for (i = 0; i < eth_dev->data->nb_rx_queues; i++) 359 rte_tel_data_add_array_int(rxq_state, 360 eth_dev->data->rx_queue_state[i]); 361 362 rte_tel_data_start_array(txq_state, RTE_TEL_INT_VAL); 363 for (i = 0; i < eth_dev->data->nb_tx_queues; i++) 364 rte_tel_data_add_array_int(txq_state, 365 eth_dev->data->tx_queue_state[i]); 366 367 rte_tel_data_add_dict_container(d, "rxq_state", rxq_state, 0); 368 rte_tel_data_add_dict_container(d, "txq_state", txq_state, 0); 369 rte_tel_data_add_dict_int(d, "numa_node", eth_dev->data->numa_node); 370 rte_tel_data_add_dict_uint_hex(d, "dev_flags", 371 eth_dev->data->dev_flags, 0); 372 373 eth_dev_parse_rx_offloads(eth_dev->data->dev_conf.rxmode.offloads, 374 rx_offload); 375 rte_tel_data_add_dict_container(d, "rx_offloads", rx_offload, 0); 376 eth_dev_parse_tx_offloads(eth_dev->data->dev_conf.txmode.offloads, 377 tx_offload); 378 rte_tel_data_add_dict_container(d, "tx_offloads", tx_offload, 0); 379 380 rte_tel_data_add_dict_uint_hex(d, "ethdev_rss_hf", 381 eth_dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf, 0); 382 383 return 0; 384 385 free_rx_offload: 386 rte_tel_data_free(rx_offload); 387 free_txq_state: 388 rte_tel_data_free(txq_state); 389 free_rxq_state: 390 rte_tel_data_free(rxq_state); 391 392 return -ENOMEM; 393 } 394 395 static int 396 eth_dev_handle_port_macs(const char *cmd __rte_unused, 397 const char *params, 398 struct rte_tel_data *d) 399 { 400 char mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; 401 struct rte_eth_dev_info dev_info; 402 struct rte_eth_dev *eth_dev; 403 uint16_t port_id; 404 char *end_param; 405 uint32_t i; 406 int ret; 407 408 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 409 if (ret < 0) 410 return ret; 411 412 ret = rte_eth_dev_info_get(port_id, &dev_info); 413 if (ret != 0) 414 return ret; 415 416 eth_dev = &rte_eth_devices[port_id]; 417 rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 418 for (i = 0; i < dev_info.max_mac_addrs; i++) { 419 if (rte_is_zero_ether_addr(ð_dev->data->mac_addrs[i])) 420 continue; 421 422 rte_ether_format_addr(mac_addr, sizeof(mac_addr), 423 ð_dev->data->mac_addrs[i]); 424 rte_tel_data_add_array_string(d, mac_addr); 425 } 426 427 return 0; 428 } 429 430 static int 431 eth_dev_handle_port_flow_ctrl(const char *cmd __rte_unused, 432 const char *params, 433 struct rte_tel_data *d) 434 { 435 struct rte_eth_fc_conf fc_conf; 436 uint16_t port_id; 437 char *end_param; 438 bool rx_fc_en; 439 bool tx_fc_en; 440 int ret; 441 442 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 443 if (ret < 0) 444 return ret; 445 446 ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf); 447 if (ret != 0) { 448 RTE_ETHDEV_LOG_LINE(ERR, 449 "Failed to get flow ctrl info, ret = %d", ret); 450 return ret; 451 } 452 453 rx_fc_en = fc_conf.mode == RTE_ETH_FC_RX_PAUSE || 454 fc_conf.mode == RTE_ETH_FC_FULL; 455 tx_fc_en = fc_conf.mode == RTE_ETH_FC_TX_PAUSE || 456 fc_conf.mode == RTE_ETH_FC_FULL; 457 458 rte_tel_data_start_dict(d); 459 rte_tel_data_add_dict_uint_hex(d, "high_waterline", fc_conf.high_water, 0); 460 rte_tel_data_add_dict_uint_hex(d, "low_waterline", fc_conf.low_water, 0); 461 rte_tel_data_add_dict_uint_hex(d, "pause_time", fc_conf.pause_time, 0); 462 rte_tel_data_add_dict_string(d, "send_xon", fc_conf.send_xon ? "on" : "off"); 463 rte_tel_data_add_dict_string(d, "mac_ctrl_frame_fwd", 464 fc_conf.mac_ctrl_frame_fwd ? "on" : "off"); 465 rte_tel_data_add_dict_string(d, "rx_pause", rx_fc_en ? "on" : "off"); 466 rte_tel_data_add_dict_string(d, "tx_pause", tx_fc_en ? "on" : "off"); 467 rte_tel_data_add_dict_string(d, "autoneg", fc_conf.autoneg ? "on" : "off"); 468 469 return 0; 470 } 471 472 static int 473 ethdev_parse_queue_params(const char *params, bool is_rx, 474 uint16_t *port_id, uint16_t *queue_id) 475 { 476 struct rte_eth_dev *dev; 477 const char *qid_param; 478 uint16_t nb_queues; 479 char *end_param; 480 uint64_t qid; 481 int ret; 482 483 ret = eth_dev_parse_port_params(params, port_id, &end_param, true); 484 if (ret < 0) 485 return ret; 486 487 dev = &rte_eth_devices[*port_id]; 488 nb_queues = is_rx ? dev->data->nb_rx_queues : dev->data->nb_tx_queues; 489 if (nb_queues == 1 && *end_param == '\0') 490 qid = 0; 491 else { 492 qid_param = strtok(end_param, ","); 493 if (!qid_param || strlen(qid_param) == 0 || !isdigit(*qid_param)) 494 return -EINVAL; 495 496 qid = strtoul(qid_param, &end_param, 0); 497 } 498 if (*end_param != '\0') 499 RTE_ETHDEV_LOG_LINE(NOTICE, 500 "Extra parameters passed to ethdev telemetry command, ignoring"); 501 502 if (qid >= UINT16_MAX) 503 return -EINVAL; 504 505 *queue_id = qid; 506 return 0; 507 } 508 509 static int 510 eth_dev_add_burst_mode(uint16_t port_id, uint16_t queue_id, 511 bool is_rx, struct rte_tel_data *d) 512 { 513 struct rte_eth_burst_mode mode; 514 int ret; 515 516 if (is_rx) 517 ret = rte_eth_rx_burst_mode_get(port_id, queue_id, &mode); 518 else 519 ret = rte_eth_tx_burst_mode_get(port_id, queue_id, &mode); 520 521 if (ret == -ENOTSUP) 522 return 0; 523 524 if (ret != 0) { 525 RTE_ETHDEV_LOG_LINE(ERR, 526 "Failed to get burst mode for port %u", port_id); 527 return ret; 528 } 529 530 rte_tel_data_add_dict_uint(d, "burst_flags", mode.flags); 531 rte_tel_data_add_dict_string(d, "burst_mode", mode.info); 532 return 0; 533 } 534 535 static int 536 eth_dev_handle_port_rxq(const char *cmd __rte_unused, 537 const char *params, 538 struct rte_tel_data *d) 539 { 540 struct rte_eth_thresh *rx_thresh; 541 struct rte_eth_rxconf *rxconf; 542 struct rte_eth_rxq_info qinfo; 543 struct rte_tel_data *offload; 544 uint16_t port_id, queue_id; 545 int ret; 546 547 ret = ethdev_parse_queue_params(params, true, &port_id, &queue_id); 548 if (ret != 0) 549 return ret; 550 551 ret = rte_eth_rx_queue_info_get(port_id, queue_id, &qinfo); 552 if (ret != 0) 553 return ret; 554 555 rte_tel_data_start_dict(d); 556 rte_tel_data_add_dict_string(d, "mempool_name", qinfo.mp->name); 557 rte_tel_data_add_dict_uint(d, "socket_id", qinfo.mp->socket_id); 558 559 rx_thresh = &qinfo.conf.rx_thresh; 560 rte_tel_data_add_dict_uint(d, "host_threshold", rx_thresh->hthresh); 561 rte_tel_data_add_dict_uint(d, "prefetch_threshold", rx_thresh->pthresh); 562 rte_tel_data_add_dict_uint(d, "writeback_threshold", rx_thresh->wthresh); 563 564 rxconf = &qinfo.conf; 565 rte_tel_data_add_dict_uint(d, "free_threshold", rxconf->rx_free_thresh); 566 rte_tel_data_add_dict_string(d, "rx_drop_en", 567 rxconf->rx_drop_en == 0 ? "off" : "on"); 568 rte_tel_data_add_dict_string(d, "deferred_start", 569 rxconf->rx_deferred_start == 0 ? "off" : "on"); 570 rte_tel_data_add_dict_uint(d, "rx_nseg", rxconf->rx_nseg); 571 rte_tel_data_add_dict_uint(d, "share_group", rxconf->share_group); 572 rte_tel_data_add_dict_uint(d, "share_qid", rxconf->share_qid); 573 574 offload = rte_tel_data_alloc(); 575 if (offload == NULL) 576 return -ENOMEM; 577 578 eth_dev_parse_rx_offloads(rxconf->offloads, offload); 579 rte_tel_data_add_dict_container(d, "offloads", offload, 0); 580 581 rte_tel_data_add_dict_uint(d, "rx_nmempool", rxconf->rx_nmempool); 582 583 rte_tel_data_add_dict_string(d, "scattered_rx", 584 qinfo.scattered_rx == 0 ? "off" : "on"); 585 rte_tel_data_add_dict_uint(d, "queue_state", qinfo.queue_state); 586 rte_tel_data_add_dict_uint(d, "nb_desc", qinfo.nb_desc); 587 rte_tel_data_add_dict_uint(d, "rx_buf_size", qinfo.rx_buf_size); 588 rte_tel_data_add_dict_uint(d, "avail_thresh", qinfo.avail_thresh); 589 590 ret = eth_dev_add_burst_mode(port_id, queue_id, true, d); 591 if (ret != 0) 592 rte_tel_data_free(offload); 593 594 return ret; 595 } 596 597 static int 598 eth_dev_handle_port_txq(const char *cmd __rte_unused, 599 const char *params, 600 struct rte_tel_data *d) 601 { 602 struct rte_eth_thresh *tx_thresh; 603 struct rte_eth_txconf *txconf; 604 struct rte_eth_txq_info qinfo; 605 struct rte_tel_data *offload; 606 uint16_t port_id, queue_id; 607 int ret; 608 609 ret = ethdev_parse_queue_params(params, false, &port_id, &queue_id); 610 if (ret != 0) 611 return ret; 612 613 ret = rte_eth_tx_queue_info_get(port_id, queue_id, &qinfo); 614 if (ret != 0) 615 return ret; 616 617 rte_tel_data_start_dict(d); 618 tx_thresh = &qinfo.conf.tx_thresh; 619 txconf = &qinfo.conf; 620 rte_tel_data_add_dict_uint(d, "host_threshold", tx_thresh->hthresh); 621 rte_tel_data_add_dict_uint(d, "prefetch_threshold", tx_thresh->pthresh); 622 rte_tel_data_add_dict_uint(d, "writeback_threshold", tx_thresh->wthresh); 623 rte_tel_data_add_dict_uint(d, "rs_threshold", txconf->tx_rs_thresh); 624 rte_tel_data_add_dict_uint(d, "free_threshold", txconf->tx_free_thresh); 625 rte_tel_data_add_dict_string(d, "deferred_start", 626 txconf->tx_deferred_start == 0 ? "off" : "on"); 627 628 offload = rte_tel_data_alloc(); 629 if (offload == NULL) 630 return -ENOMEM; 631 632 eth_dev_parse_tx_offloads(txconf->offloads, offload); 633 rte_tel_data_add_dict_container(d, "offloads", offload, 0); 634 635 rte_tel_data_add_dict_uint(d, "queue_state", qinfo.queue_state); 636 rte_tel_data_add_dict_uint(d, "nb_desc", qinfo.nb_desc); 637 638 ret = eth_dev_add_burst_mode(port_id, queue_id, false, d); 639 if (ret != 0) 640 rte_tel_data_free(offload); 641 642 return 0; 643 } 644 645 static int 646 eth_dev_add_dcb_tc(struct rte_eth_dcb_info *dcb_info, struct rte_tel_data *d) 647 { 648 struct rte_tel_data *tcds[RTE_ETH_DCB_NUM_TCS] = {NULL}; 649 struct rte_eth_dcb_tc_queue_mapping *tcq; 650 char bw_percent[RTE_TEL_MAX_STRING_LEN]; 651 char name[RTE_TEL_MAX_STRING_LEN]; 652 struct rte_tel_data *tcd; 653 uint32_t i; 654 655 for (i = 0; i < dcb_info->nb_tcs; i++) { 656 tcd = rte_tel_data_alloc(); 657 if (tcd == NULL) { 658 while (i-- > 0) 659 rte_tel_data_free(tcds[i]); 660 return -ENOMEM; 661 } 662 663 tcds[i] = tcd; 664 rte_tel_data_start_dict(tcd); 665 666 rte_tel_data_add_dict_uint(tcd, "priority", dcb_info->prio_tc[i]); 667 snprintf(bw_percent, RTE_TEL_MAX_STRING_LEN, 668 "%u%%", dcb_info->tc_bws[i]); 669 rte_tel_data_add_dict_string(tcd, "bw_percent", bw_percent); 670 671 tcq = &dcb_info->tc_queue; 672 rte_tel_data_add_dict_uint(tcd, "rxq_base", tcq->tc_rxq[0][i].base); 673 rte_tel_data_add_dict_uint(tcd, "txq_base", tcq->tc_txq[0][i].base); 674 rte_tel_data_add_dict_uint(tcd, "nb_rxq", tcq->tc_rxq[0][i].nb_queue); 675 rte_tel_data_add_dict_uint(tcd, "nb_txq", tcq->tc_txq[0][i].nb_queue); 676 677 snprintf(name, RTE_TEL_MAX_STRING_LEN, "tc%u", i); 678 rte_tel_data_add_dict_container(d, name, tcd, 0); 679 } 680 681 return 0; 682 } 683 684 static int 685 eth_dev_add_dcb_info(uint16_t port_id, struct rte_tel_data *d) 686 { 687 struct rte_eth_dcb_info dcb_info; 688 int ret; 689 690 ret = rte_eth_dev_get_dcb_info(port_id, &dcb_info); 691 if (ret != 0) { 692 RTE_ETHDEV_LOG_LINE(ERR, 693 "Failed to get dcb info, ret = %d", ret); 694 return ret; 695 } 696 697 rte_tel_data_start_dict(d); 698 rte_tel_data_add_dict_uint(d, "tc_num", dcb_info.nb_tcs); 699 700 if (dcb_info.nb_tcs > 0) 701 return eth_dev_add_dcb_tc(&dcb_info, d); 702 703 return 0; 704 } 705 706 static int 707 eth_dev_handle_port_dcb(const char *cmd __rte_unused, 708 const char *params, 709 struct rte_tel_data *d) 710 { 711 uint16_t port_id; 712 char *end_param; 713 int ret; 714 715 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 716 if (ret < 0) 717 return ret; 718 719 return eth_dev_add_dcb_info(port_id, d); 720 } 721 722 static int 723 eth_dev_add_rss_info(struct rte_eth_rss_conf *rss_conf, struct rte_tel_data *d) 724 { 725 const uint32_t key_len = rss_conf->rss_key_len * 2 + 1; 726 char *rss_key; 727 char key[3]; /* FF\0 */ 728 uint32_t i; 729 int ret; 730 731 rss_key = malloc(key_len); 732 if (rss_key == NULL) 733 return -ENOMEM; 734 735 rte_tel_data_start_dict(d); 736 rte_tel_data_add_dict_uint_hex(d, "rss_hf", rss_conf->rss_hf, 0); 737 rte_tel_data_add_dict_uint(d, "rss_key_len", rss_conf->rss_key_len); 738 739 memset(rss_key, 0, key_len); 740 for (i = 0; i < rss_conf->rss_key_len; i++) { 741 ret = snprintf(key, 3, "%02x", rss_conf->rss_key[i]); 742 if (ret < 0) 743 goto free_rss_key; 744 strlcat(rss_key, key, key_len); 745 } 746 ret = rte_tel_data_add_dict_string(d, "rss_key", rss_key); 747 748 free_rss_key: 749 free(rss_key); 750 751 return ret; 752 } 753 754 static int 755 eth_dev_handle_port_rss_info(const char *cmd __rte_unused, 756 const char *params, 757 struct rte_tel_data *d) 758 { 759 struct rte_eth_dev_info dev_info; 760 struct rte_eth_rss_conf rss_conf; 761 uint8_t key_len; 762 uint16_t port_id; 763 char *end_param; 764 int ret; 765 766 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 767 if (ret < 0) 768 return ret; 769 770 ret = rte_eth_dev_info_get(port_id, &dev_info); 771 if (ret != 0) { 772 RTE_ETHDEV_LOG_LINE(ERR, 773 "Failed to get device info, ret = %d", ret); 774 return ret; 775 } 776 777 key_len = dev_info.hash_key_size ? dev_info.hash_key_size : 40; 778 rss_conf.rss_key_len = key_len; 779 rss_conf.rss_key = malloc(key_len); 780 if (rss_conf.rss_key == NULL) 781 return -ENOMEM; 782 783 ret = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf); 784 if (ret != 0) { 785 free(rss_conf.rss_key); 786 return ret; 787 } 788 789 ret = eth_dev_add_rss_info(&rss_conf, d); 790 free(rss_conf.rss_key); 791 return ret; 792 } 793 794 static const char * 795 eth_dev_fec_capa_to_string(uint32_t fec_capa) 796 { 797 uint32_t i; 798 799 for (i = 0; i < RTE_DIM(rte_eth_fec_capa_name); i++) { 800 if ((fec_capa & rte_eth_fec_capa_name[i].capa) != 0) 801 return rte_eth_fec_capa_name[i].name; 802 } 803 804 return "unknown"; 805 } 806 807 static void 808 eth_dev_fec_capas_to_string(uint32_t fec_capa, char *fec_name, uint32_t len) 809 { 810 bool valid = false; 811 size_t count = 0; 812 uint32_t i; 813 814 for (i = 0; i < RTE_DIM(rte_eth_fec_capa_name); i++) { 815 if ((fec_capa & rte_eth_fec_capa_name[i].capa) != 0) { 816 strlcat(fec_name, rte_eth_fec_capa_name[i].name, len); 817 count = strlcat(fec_name, " ", len); 818 valid = true; 819 } 820 } 821 822 if (!valid) 823 count = snprintf(fec_name, len, "unknown "); 824 825 if (count >= len) { 826 RTE_ETHDEV_LOG_LINE(WARNING, "FEC capa names may be truncated"); 827 count = len; 828 } 829 830 fec_name[count - 1] = '\0'; 831 } 832 833 static int 834 eth_dev_get_fec_capability(uint16_t port_id, struct rte_tel_data *d) 835 { 836 struct rte_eth_fec_capa *speed_fec_capa; 837 char fec_name[RTE_TEL_MAX_STRING_LEN]; 838 char speed[RTE_TEL_MAX_STRING_LEN]; 839 uint32_t capa_num; 840 uint32_t i, j; 841 int ret; 842 843 ret = rte_eth_fec_get_capability(port_id, NULL, 0); 844 if (ret <= 0) 845 return ret == 0 ? -EINVAL : ret; 846 847 capa_num = ret; 848 speed_fec_capa = calloc(capa_num, sizeof(struct rte_eth_fec_capa)); 849 if (speed_fec_capa == NULL) 850 return -ENOMEM; 851 852 ret = rte_eth_fec_get_capability(port_id, speed_fec_capa, capa_num); 853 if (ret <= 0) { 854 ret = ret == 0 ? -EINVAL : ret; 855 goto out; 856 } 857 858 for (i = 0; i < capa_num; i++) { 859 memset(fec_name, 0, RTE_TEL_MAX_STRING_LEN); 860 eth_dev_fec_capas_to_string(speed_fec_capa[i].capa, fec_name, 861 RTE_TEL_MAX_STRING_LEN); 862 863 memset(speed, 0, RTE_TEL_MAX_STRING_LEN); 864 ret = snprintf(speed, RTE_TEL_MAX_STRING_LEN, "%s", 865 rte_eth_link_speed_to_str(speed_fec_capa[i].speed)); 866 if (ret < 0) 867 goto out; 868 869 for (j = 0; j < strlen(speed); j++) { 870 if (speed[j] == ' ') 871 speed[j] = '_'; 872 } 873 874 rte_tel_data_add_dict_string(d, speed, fec_name); 875 } 876 877 out: 878 free(speed_fec_capa); 879 return ret > 0 ? 0 : ret; 880 } 881 882 static int 883 eth_dev_handle_port_fec(const char *cmd __rte_unused, 884 const char *params, 885 struct rte_tel_data *d) 886 { 887 struct rte_tel_data *fec_capas; 888 uint32_t fec_mode; 889 uint16_t port_id; 890 char *end_param; 891 int ret; 892 893 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 894 if (ret < 0) 895 return ret; 896 897 ret = rte_eth_fec_get(port_id, &fec_mode); 898 if (ret != 0) 899 return ret; 900 901 rte_tel_data_start_dict(d); 902 rte_tel_data_add_dict_string(d, "fec_mode", 903 eth_dev_fec_capa_to_string(fec_mode)); 904 905 fec_capas = rte_tel_data_alloc(); 906 if (fec_capas == NULL) 907 return -ENOMEM; 908 909 rte_tel_data_start_dict(fec_capas); 910 ret = eth_dev_get_fec_capability(port_id, fec_capas); 911 if (ret != 0) { 912 rte_tel_data_free(fec_capas); 913 return ret; 914 } 915 916 rte_tel_data_add_dict_container(d, "fec_capability", fec_capas, 0); 917 return 0; 918 } 919 920 static int 921 eth_dev_add_vlan_id(int port_id, struct rte_tel_data *d) 922 { 923 struct rte_tel_data *vlan_blks[64] = {NULL}; 924 uint16_t vlan_num, vidx, vbit, num_blks; 925 char blk_name[RTE_TEL_MAX_STRING_LEN]; 926 struct rte_vlan_filter_conf *vfc; 927 struct rte_tel_data *vlan_blk; 928 struct rte_tel_data *vd; 929 uint64_t bit_width; 930 uint64_t vlan_id; 931 932 vd = rte_tel_data_alloc(); 933 if (vd == NULL) 934 return -ENOMEM; 935 936 vfc = &rte_eth_devices[port_id].data->vlan_filter_conf; 937 bit_width = CHAR_BIT * sizeof(uint64_t); 938 vlan_num = 0; 939 num_blks = 0; 940 941 rte_tel_data_start_dict(vd); 942 for (vidx = 0; vidx < RTE_DIM(vfc->ids); vidx++) { 943 if (vfc->ids[vidx] == 0) 944 continue; 945 946 vlan_blk = rte_tel_data_alloc(); 947 if (vlan_blk == NULL) 948 goto free_all; 949 950 vlan_blks[num_blks] = vlan_blk; 951 num_blks++; 952 snprintf(blk_name, RTE_TEL_MAX_STRING_LEN, "vlan_%"PRIu64"_to_%"PRIu64"", 953 bit_width * vidx, bit_width * (vidx + 1) - 1); 954 rte_tel_data_start_array(vlan_blk, RTE_TEL_UINT_VAL); 955 rte_tel_data_add_dict_container(vd, blk_name, vlan_blk, 0); 956 957 for (vbit = 0; vbit < bit_width; vbit++) { 958 if ((vfc->ids[vidx] & RTE_BIT64(vbit)) == 0) 959 continue; 960 961 vlan_id = bit_width * vidx + vbit; 962 rte_tel_data_add_array_uint(vlan_blk, vlan_id); 963 vlan_num++; 964 } 965 } 966 967 rte_tel_data_add_dict_uint(d, "vlan_num", vlan_num); 968 rte_tel_data_add_dict_container(d, "vlan_ids", vd, 0); 969 970 return 0; 971 972 free_all: 973 while (num_blks-- > 0) 974 rte_tel_data_free(vlan_blks[num_blks]); 975 976 rte_tel_data_free(vd); 977 return -ENOMEM; 978 } 979 980 static int 981 eth_dev_handle_port_vlan(const char *cmd __rte_unused, 982 const char *params, 983 struct rte_tel_data *d) 984 { 985 struct rte_eth_txmode *txmode; 986 struct rte_eth_conf dev_conf; 987 uint16_t port_id; 988 int offload, ret; 989 char *end_param; 990 991 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 992 if (ret < 0) 993 return ret; 994 995 ret = rte_eth_dev_conf_get(port_id, &dev_conf); 996 if (ret != 0) { 997 RTE_ETHDEV_LOG_LINE(ERR, 998 "Failed to get device configuration, ret = %d", ret); 999 return ret; 1000 } 1001 1002 txmode = &dev_conf.txmode; 1003 rte_tel_data_start_dict(d); 1004 rte_tel_data_add_dict_uint(d, "pvid", txmode->pvid); 1005 rte_tel_data_add_dict_uint(d, "hw_vlan_reject_tagged", 1006 txmode->hw_vlan_reject_tagged); 1007 rte_tel_data_add_dict_uint(d, "hw_vlan_reject_untagged", 1008 txmode->hw_vlan_reject_untagged); 1009 rte_tel_data_add_dict_uint(d, "hw_vlan_insert_pvid", 1010 txmode->hw_vlan_insert_pvid); 1011 1012 offload = rte_eth_dev_get_vlan_offload(port_id); 1013 rte_tel_data_add_dict_string(d, "VLAN_STRIP", 1014 ((offload & RTE_ETH_VLAN_STRIP_OFFLOAD) != 0) ? "on" : "off"); 1015 rte_tel_data_add_dict_string(d, "VLAN_EXTEND", 1016 ((offload & RTE_ETH_VLAN_EXTEND_OFFLOAD) != 0) ? "on" : "off"); 1017 rte_tel_data_add_dict_string(d, "QINQ_STRIP", 1018 ((offload & RTE_ETH_QINQ_STRIP_OFFLOAD) != 0) ? "on" : "off"); 1019 rte_tel_data_add_dict_string(d, "VLAN_FILTER", 1020 ((offload & RTE_ETH_VLAN_FILTER_OFFLOAD) != 0) ? "on" : "off"); 1021 1022 return eth_dev_add_vlan_id(port_id, d); 1023 } 1024 1025 static void 1026 eth_dev_add_tm_caps(struct rte_tel_data *d, struct rte_tm_capabilities *cap) 1027 { 1028 rte_tel_data_add_dict_uint(d, "n_nodes_max", cap->n_nodes_max); 1029 rte_tel_data_add_dict_uint(d, "n_levels_max", cap->n_levels_max); 1030 rte_tel_data_add_dict_int(d, "non_leaf_nodes_identical", 1031 cap->non_leaf_nodes_identical); 1032 rte_tel_data_add_dict_int(d, "leaf_nodes_identical", 1033 cap->leaf_nodes_identical); 1034 rte_tel_data_add_dict_uint(d, "shaper_n_max", cap->shaper_n_max); 1035 rte_tel_data_add_dict_uint(d, "shaper_private_n_max", 1036 cap->shaper_private_n_max); 1037 rte_tel_data_add_dict_int(d, "shaper_private_dual_rate_n_max", 1038 cap->shaper_private_dual_rate_n_max); 1039 rte_tel_data_add_dict_uint(d, "shaper_private_rate_min", 1040 cap->shaper_private_rate_min); 1041 rte_tel_data_add_dict_uint(d, "shaper_private_rate_max", 1042 cap->shaper_private_rate_max); 1043 rte_tel_data_add_dict_int(d, "shaper_private_packet_mode_supported", 1044 cap->shaper_private_packet_mode_supported); 1045 rte_tel_data_add_dict_int(d, "shaper_private_byte_mode_supported", 1046 cap->shaper_private_byte_mode_supported); 1047 rte_tel_data_add_dict_uint(d, "shaper_shared_n_max", 1048 cap->shaper_shared_n_max); 1049 rte_tel_data_add_dict_uint(d, "shaper_shared_n_nodes_per_shaper_max", 1050 cap->shaper_shared_n_nodes_per_shaper_max); 1051 rte_tel_data_add_dict_uint(d, "shaper_shared_n_shapers_per_node_max", 1052 cap->shaper_shared_n_shapers_per_node_max); 1053 rte_tel_data_add_dict_uint(d, "shaper_share_dual_rate_n_max", 1054 cap->shaper_shared_dual_rate_n_max); 1055 rte_tel_data_add_dict_uint(d, "shaper_shared_rate_min", 1056 cap->shaper_shared_rate_min); 1057 rte_tel_data_add_dict_uint(d, "shaper_shared_rate_max", 1058 cap->shaper_shared_rate_max); 1059 rte_tel_data_add_dict_int(d, "shaper_shared_packet_mode_supported", 1060 cap->shaper_shared_packet_mode_supported); 1061 rte_tel_data_add_dict_int(d, "shaper_shared_byte_mode_supported", 1062 cap->shaper_shared_byte_mode_supported); 1063 rte_tel_data_add_dict_int(d, "shaper_pkt_length_adjust_min", 1064 cap->shaper_pkt_length_adjust_min); 1065 rte_tel_data_add_dict_int(d, "shaper_pkt_length_adjust_max", 1066 cap->shaper_pkt_length_adjust_max); 1067 rte_tel_data_add_dict_uint(d, "sched_n_children_max", 1068 cap->sched_n_children_max); 1069 rte_tel_data_add_dict_uint(d, "sched_sp_n_priorities_max", 1070 cap->sched_sp_n_priorities_max); 1071 rte_tel_data_add_dict_uint(d, "sched_wfq_n_children_per_group_max", 1072 cap->sched_wfq_n_children_per_group_max); 1073 rte_tel_data_add_dict_uint(d, "sched_wfq_n_groups_max", 1074 cap->sched_wfq_n_groups_max); 1075 rte_tel_data_add_dict_uint(d, "sched_wfq_weight_max", 1076 cap->sched_wfq_weight_max); 1077 rte_tel_data_add_dict_int(d, "sched_wfq_packet_mode_supported", 1078 cap->sched_wfq_packet_mode_supported); 1079 rte_tel_data_add_dict_int(d, "sched_wfq_byte_mode_supported", 1080 cap->sched_wfq_byte_mode_supported); 1081 rte_tel_data_add_dict_int(d, "cman_wred_packet_mode_supported", 1082 cap->cman_wred_packet_mode_supported); 1083 rte_tel_data_add_dict_int(d, "cman_wred_byte_mode_supported", 1084 cap->cman_wred_byte_mode_supported); 1085 rte_tel_data_add_dict_int(d, "cman_head_drop_supported", 1086 cap->cman_head_drop_supported); 1087 rte_tel_data_add_dict_uint(d, "cman_wred_context_n_max", 1088 cap->cman_wred_context_n_max); 1089 rte_tel_data_add_dict_uint(d, "cman_wred_context_private_n_max", 1090 cap->cman_wred_context_private_n_max); 1091 rte_tel_data_add_dict_uint(d, "cman_wred_context_shared_n_max", 1092 cap->cman_wred_context_shared_n_max); 1093 rte_tel_data_add_dict_uint(d, "cman_wred_context_shared_n_nodes_per_context_max", 1094 cap->cman_wred_context_shared_n_nodes_per_context_max); 1095 rte_tel_data_add_dict_uint(d, "cman_wred_context_shared_n_contexts_per_node_max", 1096 cap->cman_wred_context_shared_n_contexts_per_node_max); 1097 rte_tel_data_add_dict_uint_hex(d, "dynamic_update", cap->dynamic_update_mask, 0); 1098 rte_tel_data_add_dict_uint_hex(d, "stats_mask", cap->stats_mask, 0); 1099 } 1100 1101 static int 1102 eth_dev_handle_port_tm_caps(const char *cmd __rte_unused, 1103 const char *params, 1104 struct rte_tel_data *d) 1105 { 1106 struct rte_tm_capabilities cap = {0}; 1107 struct rte_tm_error error = {0}; 1108 uint16_t port_id; 1109 char *end_param; 1110 int ret; 1111 1112 ret = eth_dev_parse_port_params(params, &port_id, &end_param, false); 1113 if (ret != 0) 1114 return ret; 1115 1116 ret = rte_tm_capabilities_get(port_id, &cap, &error); 1117 if (ret != 0) { 1118 RTE_ETHDEV_LOG_LINE(ERR, "error: %s, error type: %u", 1119 error.message ? error.message : "no stated reason", 1120 error.type); 1121 return ret; 1122 } 1123 1124 rte_tel_data_start_dict(d); 1125 eth_dev_add_tm_caps(d, &cap); 1126 1127 return 0; 1128 } 1129 1130 static void 1131 eth_dev_add_tm_level_basic_caps(struct rte_tel_data *d, 1132 struct rte_tm_level_capabilities *cap) 1133 { 1134 rte_tel_data_add_dict_uint(d, "n_nodes_max", cap->n_nodes_max); 1135 rte_tel_data_add_dict_uint(d, "n_nodes_nonleaf_max", 1136 cap->n_nodes_nonleaf_max); 1137 rte_tel_data_add_dict_uint(d, "n_nodes_leaf_max", cap->n_nodes_leaf_max); 1138 rte_tel_data_add_dict_int(d, "non_leaf_nodes_identical", 1139 cap->non_leaf_nodes_identical); 1140 rte_tel_data_add_dict_int(d, "leaf_nodes_identical", 1141 cap->leaf_nodes_identical); 1142 } 1143 1144 static void 1145 eth_dev_add_tm_level_nonleaf_caps(struct rte_tel_data *nonleaf, 1146 struct rte_tm_level_capabilities *cap) 1147 { 1148 rte_tel_data_add_dict_int(nonleaf, "shaper_private_supported", 1149 cap->nonleaf.shaper_private_supported); 1150 rte_tel_data_add_dict_int(nonleaf, "shaper_private_dual_rate_supported", 1151 cap->nonleaf.shaper_private_dual_rate_supported); 1152 rte_tel_data_add_dict_uint(nonleaf, "shaper_private_rate_min", 1153 cap->nonleaf.shaper_private_rate_min); 1154 rte_tel_data_add_dict_uint(nonleaf, "shaper_private_rate_max", 1155 cap->nonleaf.shaper_private_rate_max); 1156 rte_tel_data_add_dict_int(nonleaf, "shaper_private_packet_mode_supported", 1157 cap->nonleaf.shaper_private_packet_mode_supported); 1158 rte_tel_data_add_dict_int(nonleaf, "shaper_private_byte_mode_supported", 1159 cap->nonleaf.shaper_private_byte_mode_supported); 1160 rte_tel_data_add_dict_uint(nonleaf, "shaper_shared_n_max", 1161 cap->nonleaf.shaper_shared_n_max); 1162 rte_tel_data_add_dict_int(nonleaf, "shaper_shared_packet_mode_supported", 1163 cap->nonleaf.shaper_shared_packet_mode_supported); 1164 rte_tel_data_add_dict_int(nonleaf, "shaper_shared_byte_mode_supported", 1165 cap->nonleaf.shaper_shared_byte_mode_supported); 1166 rte_tel_data_add_dict_uint(nonleaf, "sched_n_children_max", 1167 cap->nonleaf.sched_n_children_max); 1168 rte_tel_data_add_dict_uint(nonleaf, "sched_sp_n_priorities_max", 1169 cap->nonleaf.sched_sp_n_priorities_max); 1170 rte_tel_data_add_dict_uint(nonleaf, "sched_wfq_n_children_per_group_max", 1171 cap->nonleaf.sched_wfq_n_children_per_group_max); 1172 rte_tel_data_add_dict_uint(nonleaf, "sched_wfq_n_groups_max", 1173 cap->nonleaf.sched_wfq_n_groups_max); 1174 rte_tel_data_add_dict_uint(nonleaf, "sched_wfq_weight_max", 1175 cap->nonleaf.sched_wfq_weight_max); 1176 rte_tel_data_add_dict_int(nonleaf, "sched_wfq_packet_mode_supported", 1177 cap->nonleaf.sched_wfq_packet_mode_supported); 1178 rte_tel_data_add_dict_int(nonleaf, "sched_wfq_byte_mode_supported", 1179 cap->nonleaf.sched_wfq_byte_mode_supported); 1180 rte_tel_data_add_dict_uint_hex(nonleaf, "stats_mask", 1181 cap->nonleaf.stats_mask, 0); 1182 } 1183 1184 static void 1185 eth_dev_add_tm_level_leaf_caps(struct rte_tel_data *leaf, 1186 struct rte_tm_level_capabilities *cap) 1187 { 1188 rte_tel_data_add_dict_int(leaf, "shaper_private_supported", 1189 cap->leaf.shaper_private_supported); 1190 rte_tel_data_add_dict_int(leaf, "shaper_private_dual_rate_supported", 1191 cap->leaf.shaper_private_dual_rate_supported); 1192 rte_tel_data_add_dict_uint(leaf, "shaper_private_rate_min", 1193 cap->leaf.shaper_private_rate_min); 1194 rte_tel_data_add_dict_uint(leaf, "shaper_private_rate_max", 1195 cap->leaf.shaper_private_rate_max); 1196 rte_tel_data_add_dict_int(leaf, "shaper_private_packet_mode_supported", 1197 cap->leaf.shaper_private_packet_mode_supported); 1198 rte_tel_data_add_dict_int(leaf, "shaper_private_byte_mode_supported", 1199 cap->leaf.shaper_private_byte_mode_supported); 1200 rte_tel_data_add_dict_uint(leaf, "shaper_shared_n_max", 1201 cap->leaf.shaper_shared_n_max); 1202 rte_tel_data_add_dict_int(leaf, "shaper_shared_packet_mode_supported", 1203 cap->leaf.shaper_shared_packet_mode_supported); 1204 rte_tel_data_add_dict_int(leaf, "shaper_shared_byte_mode_supported", 1205 cap->leaf.shaper_shared_byte_mode_supported); 1206 rte_tel_data_add_dict_int(leaf, "cman_wred_packet_mode_supported", 1207 cap->leaf.cman_wred_packet_mode_supported); 1208 rte_tel_data_add_dict_int(leaf, "cman_wred_byte_mode_supported", 1209 cap->leaf.cman_wred_byte_mode_supported); 1210 rte_tel_data_add_dict_int(leaf, "cman_head_drop_supported", 1211 cap->leaf.cman_head_drop_supported); 1212 rte_tel_data_add_dict_int(leaf, "cman_wred_context_private_supported", 1213 cap->leaf.cman_wred_context_private_supported); 1214 rte_tel_data_add_dict_uint(leaf, "cman_wred_context_shared_n_max", 1215 cap->leaf.cman_wred_context_shared_n_max); 1216 rte_tel_data_add_dict_uint_hex(leaf, "stats_mask", 1217 cap->leaf.stats_mask, 0); 1218 } 1219 1220 static int 1221 eth_dev_parse_tm_params(char *params, uint32_t *result) 1222 { 1223 const char *splited_param; 1224 uint64_t ret; 1225 1226 splited_param = strtok(params, ","); 1227 if (!splited_param || strlen(splited_param) == 0 || !isdigit(*splited_param)) 1228 return -EINVAL; 1229 1230 ret = strtoul(splited_param, ¶ms, 0); 1231 if (*params != '\0') 1232 RTE_ETHDEV_LOG_LINE(NOTICE, 1233 "Extra parameters passed to ethdev telemetry command, ignoring"); 1234 1235 if (ret >= UINT32_MAX) 1236 return -EINVAL; 1237 1238 *result = ret; 1239 return 0; 1240 } 1241 1242 static int 1243 eth_dev_handle_port_tm_level_caps(const char *cmd __rte_unused, 1244 const char *params, 1245 struct rte_tel_data *d) 1246 { 1247 struct rte_tm_level_capabilities cap = {0}; 1248 struct rte_tm_error error = {0}; 1249 struct rte_tel_data *nonleaf; 1250 struct rte_tel_data *leaf; 1251 uint32_t level_id; 1252 uint16_t port_id; 1253 char *end_param; 1254 int ret; 1255 1256 ret = eth_dev_parse_port_params(params, &port_id, &end_param, true); 1257 if (ret != 0) 1258 return ret; 1259 1260 ret = eth_dev_parse_tm_params(end_param, &level_id); 1261 if (ret != 0) 1262 return ret; 1263 1264 ret = rte_tm_level_capabilities_get(port_id, level_id, &cap, &error); 1265 if (ret != 0) { 1266 RTE_ETHDEV_LOG_LINE(ERR, "error: %s, error type: %u", 1267 error.message ? error.message : "no stated reason", 1268 error.type); 1269 return ret; 1270 } 1271 1272 rte_tel_data_start_dict(d); 1273 eth_dev_add_tm_level_basic_caps(d, &cap); 1274 1275 nonleaf = rte_tel_data_alloc(); 1276 if (nonleaf == NULL) 1277 return -ENOMEM; 1278 1279 rte_tel_data_start_dict(nonleaf); 1280 eth_dev_add_tm_level_nonleaf_caps(nonleaf, &cap); 1281 rte_tel_data_add_dict_container(d, "nonleaf_cap", nonleaf, 0); 1282 1283 leaf = rte_tel_data_alloc(); 1284 if (leaf == NULL) { 1285 rte_tel_data_free(nonleaf); 1286 return -ENOMEM; 1287 } 1288 1289 rte_tel_data_start_dict(leaf); 1290 eth_dev_add_tm_level_leaf_caps(leaf, &cap); 1291 rte_tel_data_add_dict_container(d, "leaf_cap", leaf, 0); 1292 1293 return 0; 1294 } 1295 1296 static void 1297 eth_dev_add_tm_node_basic_caps(struct rte_tel_data *node_data, 1298 struct rte_tm_node_capabilities *capnode) 1299 { 1300 rte_tel_data_add_dict_int(node_data, "shaper_private_supported", 1301 capnode->shaper_private_supported); 1302 rte_tel_data_add_dict_int(node_data, "shaper_private_dual_rate_supported", 1303 capnode->shaper_private_dual_rate_supported); 1304 rte_tel_data_add_dict_uint(node_data, "shaper_private_rate_min", 1305 capnode->shaper_private_rate_min); 1306 rte_tel_data_add_dict_uint(node_data, "shaper_private_rate_max", 1307 capnode->shaper_private_rate_max); 1308 rte_tel_data_add_dict_int(node_data, "shaper_private_packet_mode_supported", 1309 capnode->shaper_private_packet_mode_supported); 1310 rte_tel_data_add_dict_int(node_data, "shaper_private_byte_mode_supported", 1311 capnode->shaper_private_byte_mode_supported); 1312 rte_tel_data_add_dict_uint(node_data, "shaper_shared_n_max", 1313 capnode->shaper_shared_n_max); 1314 rte_tel_data_add_dict_int(node_data, "shaper_shared_packet_mode_supported", 1315 capnode->shaper_shared_packet_mode_supported); 1316 rte_tel_data_add_dict_int(node_data, "shaper_shared_byte_mode_supported", 1317 capnode->shaper_shared_byte_mode_supported); 1318 rte_tel_data_add_dict_uint_hex(node_data, "stats_mask", 1319 capnode->stats_mask, 0); 1320 } 1321 1322 static void 1323 eth_dev_add_tm_type_node_caps(struct rte_tel_data *d, int is_leaf, 1324 struct rte_tm_node_capabilities *cap) 1325 { 1326 rte_tel_data_add_dict_string(d, "node_type", 1327 is_leaf == 0 ? "nonleaf" : "leaf"); 1328 if (is_leaf == 0) { 1329 rte_tel_data_add_dict_uint(d, "children_max", 1330 cap->nonleaf.sched_n_children_max); 1331 rte_tel_data_add_dict_uint(d, "priorities_max", 1332 cap->nonleaf.sched_sp_n_priorities_max); 1333 rte_tel_data_add_dict_uint(d, "sched_wfq_n_children_per_group_max", 1334 cap->nonleaf.sched_wfq_n_children_per_group_max); 1335 rte_tel_data_add_dict_uint(d, "sched_wfq_n_groups_max", 1336 cap->nonleaf.sched_wfq_n_groups_max); 1337 rte_tel_data_add_dict_uint(d, "sched_wfq_weight_max", 1338 cap->nonleaf.sched_wfq_weight_max); 1339 rte_tel_data_add_dict_int(d, "sched_wfq_packet_mode_supported", 1340 cap->nonleaf.sched_wfq_packet_mode_supported); 1341 rte_tel_data_add_dict_int(d, "sched_wfq_byte_mode_supported", 1342 cap->nonleaf.sched_wfq_byte_mode_supported); 1343 } else { 1344 rte_tel_data_add_dict_int(d, "cman_wred_packet_mode_supported", 1345 cap->leaf.cman_wred_packet_mode_supported); 1346 rte_tel_data_add_dict_int(d, "cman_wred_byte_mode_supported", 1347 cap->leaf.cman_wred_byte_mode_supported); 1348 rte_tel_data_add_dict_int(d, "cman_head_drop_supported", 1349 cap->leaf.cman_head_drop_supported); 1350 rte_tel_data_add_dict_int(d, "cman_wred_context_private_supported", 1351 cap->leaf.cman_wred_context_private_supported); 1352 rte_tel_data_add_dict_uint(d, "cman_wred_context_shared_n_max", 1353 cap->leaf.cman_wred_context_shared_n_max); 1354 } 1355 } 1356 1357 static int 1358 eth_dev_handle_port_tm_node_caps(const char *cmd __rte_unused, 1359 const char *params, 1360 struct rte_tel_data *d) 1361 { 1362 struct rte_tm_node_capabilities cap = {0}; 1363 struct rte_tm_error error = {0}; 1364 uint32_t node_id; 1365 uint16_t port_id; 1366 char *end_param; 1367 int is_leaf; 1368 int ret; 1369 1370 ret = eth_dev_parse_port_params(params, &port_id, &end_param, true); 1371 if (ret != 0) 1372 return ret; 1373 1374 ret = eth_dev_parse_tm_params(end_param, &node_id); 1375 if (ret != 0) 1376 return ret; 1377 1378 ret = rte_tm_node_capabilities_get(port_id, node_id, &cap, &error); 1379 if (ret != 0) 1380 goto out; 1381 1382 ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error); 1383 if (ret != 0) 1384 goto out; 1385 1386 rte_tel_data_start_dict(d); 1387 eth_dev_add_tm_node_basic_caps(d, &cap); 1388 eth_dev_add_tm_type_node_caps(d, is_leaf, &cap); 1389 1390 return 0; 1391 out: 1392 RTE_ETHDEV_LOG_LINE(WARNING, "error: %s, error type: %u", 1393 error.message ? error.message : "no stated reason", 1394 error.type); 1395 return ret; 1396 } 1397 1398 static void 1399 eth_dev_add_reg_data(struct rte_tel_data *d, struct rte_dev_reg_info *reg_info, 1400 uint32_t idx) 1401 { 1402 if (reg_info->width == sizeof(uint32_t)) 1403 rte_tel_data_add_dict_uint_hex(d, reg_info->names[idx].name, 1404 *((uint32_t *)reg_info->data + idx), 0); 1405 else 1406 rte_tel_data_add_dict_uint_hex(d, reg_info->names[idx].name, 1407 *((uint64_t *)reg_info->data + idx), 0); 1408 } 1409 1410 static int 1411 eth_dev_store_regs(struct rte_tel_data *d, struct rte_dev_reg_info *reg_info) 1412 { 1413 struct rte_tel_data *groups[RTE_TEL_MAX_DICT_ENTRIES]; 1414 char group_name[RTE_TEL_MAX_STRING_LEN] = {0}; 1415 struct rte_tel_data *group = NULL; 1416 uint32_t grp_num = 0; 1417 uint32_t i, max_cap; 1418 int ret; 1419 1420 rte_tel_data_start_dict(d); 1421 rte_tel_data_add_dict_uint(d, "register_length", reg_info->length); 1422 rte_tel_data_add_dict_uint(d, "register_width", reg_info->width); 1423 rte_tel_data_add_dict_uint_hex(d, "register_offset", reg_info->offset, 0); 1424 rte_tel_data_add_dict_uint_hex(d, "version", reg_info->version, 0); 1425 1426 max_cap = (RTE_TEL_MAX_DICT_ENTRIES - 4) * RTE_TEL_MAX_DICT_ENTRIES; 1427 if (reg_info->length > max_cap) { 1428 RTE_ETHDEV_LOG_LINE(WARNING, 1429 "Registers to be displayed are reduced from %u to %u due to limited capacity", 1430 reg_info->length, max_cap); 1431 reg_info->length = max_cap; 1432 } 1433 1434 for (i = 0; i < reg_info->length; i++) { 1435 if (i % RTE_TEL_MAX_DICT_ENTRIES != 0) { 1436 eth_dev_add_reg_data(group, reg_info, i); 1437 continue; 1438 } 1439 1440 group = rte_tel_data_alloc(); 1441 if (group == NULL) { 1442 ret = -ENOMEM; 1443 RTE_ETHDEV_LOG_LINE(WARNING, "No enough memory for group data"); 1444 goto out; 1445 } 1446 groups[grp_num++] = group; 1447 rte_tel_data_start_dict(group); 1448 eth_dev_add_reg_data(group, reg_info, i); 1449 } 1450 1451 for (i = 0; i < grp_num; i++) { 1452 snprintf(group_name, RTE_TEL_MAX_STRING_LEN, "group_%u", i); 1453 rte_tel_data_add_dict_container(d, group_name, groups[i], 0); 1454 } 1455 return 0; 1456 out: 1457 for (i = 0; i < grp_num; i++) 1458 rte_tel_data_free(groups[i]); 1459 1460 return ret; 1461 } 1462 1463 static int 1464 eth_dev_get_port_regs(int port_id, struct rte_tel_data *d, char *filter) 1465 { 1466 struct rte_dev_reg_info reg_info; 1467 int ret; 1468 1469 memset(®_info, 0, sizeof(reg_info)); 1470 reg_info.filter = filter; 1471 1472 ret = rte_eth_dev_get_reg_info_ext(port_id, ®_info); 1473 if (ret != 0) { 1474 RTE_ETHDEV_LOG_LINE(ERR, "Failed to get device reg info: %d", ret); 1475 return ret; 1476 } 1477 1478 reg_info.data = calloc(reg_info.length, reg_info.width); 1479 if (reg_info.data == NULL) { 1480 RTE_ETHDEV_LOG_LINE(ERR, "Failed to allocate memory for reg_info.data"); 1481 return -ENOMEM; 1482 } 1483 1484 reg_info.names = calloc(reg_info.length, sizeof(struct rte_eth_reg_name)); 1485 if (reg_info.names == NULL) { 1486 RTE_ETHDEV_LOG_LINE(ERR, "Failed to allocate memory for reg_info.names"); 1487 free(reg_info.data); 1488 return -ENOMEM; 1489 } 1490 1491 ret = rte_eth_dev_get_reg_info_ext(port_id, ®_info); 1492 if (ret != 0) { 1493 RTE_ETHDEV_LOG_LINE(ERR, "Failed to get device reg info: %d", ret); 1494 ret = -EINVAL; 1495 goto out; 1496 } 1497 1498 ret = eth_dev_store_regs(d, ®_info); 1499 out: 1500 free(reg_info.data); 1501 free(reg_info.names); 1502 1503 return ret; 1504 } 1505 1506 static int 1507 eth_dev_handle_port_regs(const char *cmd __rte_unused, 1508 const char *params, 1509 struct rte_tel_data *d) 1510 { 1511 char *filter, *end_param; 1512 uint16_t port_id; 1513 int ret; 1514 1515 ret = eth_dev_parse_port_params(params, &port_id, &end_param, true); 1516 if (ret != 0) 1517 return ret; 1518 1519 filter = strtok(end_param, ","); 1520 if (filter != NULL && strlen(filter) == 0) 1521 filter = NULL; 1522 1523 return eth_dev_get_port_regs(port_id, d, filter); 1524 } 1525 1526 static int eth_dev_telemetry_do(const char *cmd, const char *params, void *arg, 1527 struct rte_tel_data *d) 1528 { 1529 telemetry_cb fn = arg; 1530 int ret; 1531 1532 /* Protect against port removal while invoking callback, calling ethdev API. */ 1533 rte_spinlock_lock(rte_mcfg_ethdev_get_lock()); 1534 ret = fn(cmd, params, d); 1535 rte_spinlock_unlock(rte_mcfg_ethdev_get_lock()); 1536 1537 return ret; 1538 } 1539 1540 RTE_INIT(ethdev_init_telemetry) 1541 { 1542 rte_telemetry_register_cmd_arg("/ethdev/list", 1543 eth_dev_telemetry_do, eth_dev_handle_port_list, 1544 "Returns list of available ethdev ports. Takes no parameters"); 1545 rte_telemetry_register_cmd_arg("/ethdev/stats", 1546 eth_dev_telemetry_do, eth_dev_handle_port_stats, 1547 "Returns the common stats for a port. Parameters: int port_id"); 1548 rte_telemetry_register_cmd_arg("/ethdev/xstats", 1549 eth_dev_telemetry_do, eth_dev_handle_port_xstats, 1550 "Returns the extended stats for a port. Parameters: int port_id,hide_zero=true|false(Optional for indicates hide zero xstats)"); 1551 #ifndef RTE_EXEC_ENV_WINDOWS 1552 rte_telemetry_register_cmd_arg("/ethdev/dump_priv", 1553 eth_dev_telemetry_do, eth_dev_handle_port_dump_priv, 1554 "Returns dump private information for a port. Parameters: int port_id"); 1555 #endif 1556 rte_telemetry_register_cmd_arg("/ethdev/link_status", 1557 eth_dev_telemetry_do, eth_dev_handle_port_link_status, 1558 "Returns the link status for a port. Parameters: int port_id"); 1559 rte_telemetry_register_cmd_arg("/ethdev/info", 1560 eth_dev_telemetry_do, eth_dev_handle_port_info, 1561 "Returns the device info for a port. Parameters: int port_id"); 1562 rte_telemetry_register_cmd_arg("/ethdev/module_eeprom", 1563 eth_dev_telemetry_do, eth_dev_handle_port_module_eeprom, 1564 "Returns module EEPROM info with SFF specs. Parameters: int port_id"); 1565 rte_telemetry_register_cmd_arg("/ethdev/macs", 1566 eth_dev_telemetry_do, eth_dev_handle_port_macs, 1567 "Returns the MAC addresses for a port. Parameters: int port_id"); 1568 rte_telemetry_register_cmd_arg("/ethdev/flow_ctrl", 1569 eth_dev_telemetry_do, eth_dev_handle_port_flow_ctrl, 1570 "Returns flow ctrl info for a port. Parameters: int port_id"); 1571 rte_telemetry_register_cmd_arg("/ethdev/rx_queue", 1572 eth_dev_telemetry_do, eth_dev_handle_port_rxq, 1573 "Returns Rx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); 1574 rte_telemetry_register_cmd_arg("/ethdev/tx_queue", 1575 eth_dev_telemetry_do, eth_dev_handle_port_txq, 1576 "Returns Tx queue info for a port. Parameters: int port_id, int queue_id (Optional if only one queue)"); 1577 rte_telemetry_register_cmd_arg("/ethdev/dcb", 1578 eth_dev_telemetry_do, eth_dev_handle_port_dcb, 1579 "Returns DCB info for a port. Parameters: int port_id"); 1580 rte_telemetry_register_cmd_arg("/ethdev/rss_info", 1581 eth_dev_telemetry_do, eth_dev_handle_port_rss_info, 1582 "Returns RSS info for a port. Parameters: int port_id"); 1583 rte_telemetry_register_cmd_arg("/ethdev/fec", 1584 eth_dev_telemetry_do, eth_dev_handle_port_fec, 1585 "Returns FEC info for a port. Parameters: int port_id"); 1586 rte_telemetry_register_cmd_arg("/ethdev/vlan", 1587 eth_dev_telemetry_do, eth_dev_handle_port_vlan, 1588 "Returns VLAN info for a port. Parameters: int port_id"); 1589 rte_telemetry_register_cmd_arg("/ethdev/tm_capability", 1590 eth_dev_telemetry_do, eth_dev_handle_port_tm_caps, 1591 "Returns TM Capabilities info for a port. Parameters: int port_id"); 1592 rte_telemetry_register_cmd_arg("/ethdev/tm_level_capability", 1593 eth_dev_telemetry_do, eth_dev_handle_port_tm_level_caps, 1594 "Returns TM Level Capabilities info for a port. Parameters: int port_id, int level_id (see tm_capability for the max)"); 1595 rte_telemetry_register_cmd_arg("/ethdev/tm_node_capability", 1596 eth_dev_telemetry_do, eth_dev_handle_port_tm_node_caps, 1597 "Returns TM Node Capabilities info for a port. Parameters: int port_id, int node_id (see tm_capability for the max)"); 1598 rte_telemetry_register_cmd("/ethdev/regs", eth_dev_handle_port_regs, 1599 "Returns all or filtered registers info for a port. Parameters: int port_id, string module_name (Optional if show all)"); 1600 } 1601