xref: /dpdk/lib/ethdev/rte_ethdev_telemetry.c (revision d916d27e3dca9d2e19e411fff9208929a7c7cbdf)
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 *)&eth_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(&eth_dev->data->mac_addrs[i]))
420 			continue;
421 
422 		rte_ether_format_addr(mac_addr, sizeof(mac_addr),
423 			&eth_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, &params, 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(&reg_info, 0, sizeof(reg_info));
1470 	reg_info.filter = filter;
1471 
1472 	ret = rte_eth_dev_get_reg_info_ext(port_id, &reg_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, &reg_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, &reg_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