xref: /dpdk/drivers/net/mlx5/mlx5_testpmd.c (revision 09442498ef736d0a96632cf8b8c15d8ca78a6468)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2021 6WIND S.A.
3  * Copyright 2021 Mellanox Technologies, Ltd
4  */
5 
6 #include <stdint.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #ifndef RTE_EXEC_ENV_WINDOWS
11 #include <sys/socket.h>
12 #include <sys/un.h>
13 #endif
14 
15 #include <rte_prefetch.h>
16 #include <rte_common.h>
17 #include <rte_branch_prediction.h>
18 #include <rte_ether.h>
19 #include <rte_alarm.h>
20 #include <rte_pmd_mlx5.h>
21 #include <rte_ethdev.h>
22 
23 #include "mlx5_testpmd.h"
24 #include "testpmd.h"
25 
26 static uint8_t host_shaper_avail_thresh_triggered[RTE_MAX_ETHPORTS];
27 #define SHAPER_DISABLE_DELAY_US 100000 /* 100ms */
28 
29 /**
30  * Disable the host shaper and re-arm available descriptor threshold event.
31  *
32  * @param[in] args
33  *   uint32_t integer combining port_id and rxq_id.
34  */
35 static void
36 mlx5_test_host_shaper_disable(void *args)
37 {
38 	uint32_t port_rxq_id = (uint32_t)(uintptr_t)args;
39 	uint16_t port_id = port_rxq_id & 0xffff;
40 	uint16_t qid = (port_rxq_id >> 16) & 0xffff;
41 	struct rte_eth_rxq_info qinfo;
42 	struct rte_port *port;
43 
44 	port = &ports[port_id];
45 	if (port->port_status != RTE_PORT_STARTED) {
46 		printf("%s port_status(%d) is incorrect, stop avail_thresh "
47 		       "event processing.\n",
48 		       __func__, port->port_status);
49 		return;
50 	}
51 	printf("%s disable shaper\n", __func__);
52 	if (rte_eth_rx_queue_info_get(port_id, qid, &qinfo)) {
53 		printf("rx_queue_info_get returns error\n");
54 		return;
55 	}
56 	/* Rearm the available descriptor threshold event. */
57 	if (rte_eth_rx_avail_thresh_set(port_id, qid, qinfo.avail_thresh)) {
58 		printf("config avail_thresh returns error\n");
59 		return;
60 	}
61 	/* Only disable the shaper when avail_thresh_triggered is set. */
62 	if (host_shaper_avail_thresh_triggered[port_id] &&
63 	    rte_pmd_mlx5_host_shaper_config(port_id, 0, 0))
64 		printf("%s disable shaper returns error\n", __func__);
65 }
66 
67 void
68 mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id)
69 {
70 	struct rte_eth_dev_info dev_info;
71 	uint32_t port_rxq_id = port_id | (rxq_id << 16);
72 
73 	/* Ensure it's MLX5 port. */
74 	if (rte_eth_dev_info_get(port_id, &dev_info) != 0 ||
75 	    (strncmp(dev_info.driver_name, "mlx5", 4) != 0))
76 		return;
77 	rte_eal_alarm_set(SHAPER_DISABLE_DELAY_US,
78 			  mlx5_test_host_shaper_disable,
79 			  (void *)(uintptr_t)port_rxq_id);
80 	printf("%s port_id:%u rxq_id:%u\n", __func__, port_id, rxq_id);
81 }
82 
83 /**
84  * Configure host shaper's avail_thresh_triggered and current rate.
85  *
86  * @param[in] avail_thresh_triggered
87  *   Disable/enable avail_thresh_triggered.
88  * @param[in] rate
89  *   Configure current host shaper rate.
90  * @return
91  *   On success, returns 0.
92  *   On failure, returns < 0.
93  */
94 static int
95 mlx5_test_set_port_host_shaper(uint16_t port_id, uint16_t avail_thresh_triggered, uint8_t rate)
96 {
97 	struct rte_eth_link link;
98 	bool port_id_valid = false;
99 	uint16_t pid;
100 	int ret;
101 
102 	RTE_ETH_FOREACH_DEV(pid)
103 		if (port_id == pid) {
104 			port_id_valid = true;
105 			break;
106 		}
107 	if (!port_id_valid)
108 		return -EINVAL;
109 	ret = rte_eth_link_get_nowait(port_id, &link);
110 	if (ret < 0)
111 		return ret;
112 	host_shaper_avail_thresh_triggered[port_id] = avail_thresh_triggered ? 1 : 0;
113 	if (!avail_thresh_triggered) {
114 		ret = rte_pmd_mlx5_host_shaper_config(port_id, 0,
115 		RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED));
116 	} else {
117 		ret = rte_pmd_mlx5_host_shaper_config(port_id, 1,
118 		RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED));
119 	}
120 	if (ret)
121 		return ret;
122 	ret = rte_pmd_mlx5_host_shaper_config(port_id, rate, 0);
123 	if (ret)
124 		return ret;
125 	return 0;
126 }
127 
128 #ifndef RTE_EXEC_ENV_WINDOWS
129 static const char*
130 mlx5_test_get_socket_path(char *extend)
131 {
132 	if (strstr(extend, "socket=") == extend) {
133 		const char *socket_path = strchr(extend, '=') + 1;
134 
135 		TESTPMD_LOG(DEBUG, "MLX5 socket path is %s\n", socket_path);
136 		return socket_path;
137 	}
138 
139 	TESTPMD_LOG(ERR, "Failed to extract a valid socket path from %s\n",
140 		    extend);
141 	return NULL;
142 }
143 
144 static int
145 mlx5_test_extend_devargs(char *identifier, char *extend)
146 {
147 	struct sockaddr_un un = {
148 		.sun_family = AF_UNIX,
149 	};
150 	int cmd_fd;
151 	int pd_handle;
152 	struct iovec iov = {
153 		.iov_base = &pd_handle,
154 		.iov_len = sizeof(int),
155 	};
156 	union {
157 		char buf[CMSG_SPACE(sizeof(int))];
158 		struct cmsghdr align;
159 	} control;
160 	struct msghdr msgh = {
161 		.msg_iov = NULL,
162 		.msg_iovlen = 0,
163 	};
164 	struct cmsghdr *cmsg;
165 	const char *path = mlx5_test_get_socket_path(extend + 1);
166 	size_t len = 1;
167 	int socket_fd;
168 	int ret;
169 
170 	if (path == NULL) {
171 		TESTPMD_LOG(ERR, "Invalid devargs extension is specified\n");
172 		return -1;
173 	}
174 
175 	/* Initialize IPC channel. */
176 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
177 	if (socket_fd < 0) {
178 		TESTPMD_LOG(ERR, "Failed to create unix socket: %s\n",
179 			    strerror(errno));
180 		return -1;
181 	}
182 	rte_strlcpy(un.sun_path, path, sizeof(un.sun_path));
183 	if (connect(socket_fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
184 		TESTPMD_LOG(ERR, "Failed to connect %s: %s\n", un.sun_path,
185 			    strerror(errno));
186 		close(socket_fd);
187 		return -1;
188 	}
189 
190 	/* Send the request message. */
191 	do {
192 		ret = sendmsg(socket_fd, &msgh, 0);
193 	} while (ret < 0 && errno == EINTR);
194 	if (ret < 0) {
195 		TESTPMD_LOG(ERR, "Failed to send request to (%s): %s\n", path,
196 			    strerror(errno));
197 		close(socket_fd);
198 		return -1;
199 	}
200 
201 	msgh.msg_iov = &iov;
202 	msgh.msg_iovlen = 1;
203 	msgh.msg_control = control.buf;
204 	msgh.msg_controllen = sizeof(control.buf);
205 	do {
206 		ret = recvmsg(socket_fd, &msgh, 0);
207 	} while (ret < 0);
208 	if (ret != sizeof(int) || (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
209 		TESTPMD_LOG(ERR, "truncated msg");
210 		close(socket_fd);
211 		return -1;
212 	}
213 
214 	/* Translate the FD. */
215 	cmsg = CMSG_FIRSTHDR(&msgh);
216 	if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
217 	    cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
218 		TESTPMD_LOG(ERR, "Fail to get FD using SCM_RIGHTS mechanism\n");
219 		close(socket_fd);
220 		unlink(un.sun_path);
221 		return -1;
222 	}
223 	memcpy(&cmd_fd, CMSG_DATA(cmsg), sizeof(int));
224 
225 	TESTPMD_LOG(DEBUG, "Command FD (%d) and PD handle (%d) "
226 		    "are successfully imported from remote process\n",
227 		    cmd_fd, pd_handle);
228 
229 	/* Cleanup IPC channel. */
230 	close(socket_fd);
231 
232 	/* Calculate the new length of devargs string. */
233 	len += snprintf(NULL, 0, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle);
234 	/* Extend the devargs string. */
235 	snprintf(extend, len, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle);
236 
237 	TESTPMD_LOG(DEBUG, "Attach port with extra devargs %s\n", identifier);
238 	return 0;
239 }
240 
241 static bool
242 is_delimiter_path_spaces(char *extend)
243 {
244 	while (*extend != '\0') {
245 		if (*extend != ' ')
246 			return true;
247 		extend++;
248 	}
249 	return false;
250 }
251 
252 /*
253  * Extend devargs list with "cmd_fd" and "pd_handle" coming from external
254  * process. It happens only in this format:
255  *  testpmd> mlx5 port attach (identifier) socket=<socket path>
256  * all "(identifier) socket=<socket path>" is in the same string pointed
257  * by the input parameter 'identifier'.
258  *
259  * @param identifier
260  *   Identifier of port attach command line.
261  */
262 static void
263 mlx5_test_attach_port_extend_devargs(char *identifier)
264 {
265 	char *extend;
266 
267 	if (identifier == NULL) {
268 		fprintf(stderr, "Invalid parameters are specified\n");
269 		return;
270 	}
271 
272 	extend = strchr(identifier, ' ');
273 	if (extend != NULL && is_delimiter_path_spaces(extend) &&
274 	    mlx5_test_extend_devargs(identifier, extend) < 0) {
275 		TESTPMD_LOG(ERR, "Failed to extend devargs for port %s\n",
276 			    identifier);
277 		return;
278 	}
279 
280 	attach_port(identifier);
281 }
282 #endif
283 
284 /* *** SET HOST_SHAPER FOR A PORT *** */
285 struct cmd_port_host_shaper_result {
286 	cmdline_fixed_string_t mlx5;
287 	cmdline_fixed_string_t set;
288 	cmdline_fixed_string_t port;
289 	uint16_t port_num;
290 	cmdline_fixed_string_t host_shaper;
291 	cmdline_fixed_string_t avail_thresh_triggered;
292 	uint16_t fr;
293 	cmdline_fixed_string_t rate;
294 	uint8_t rate_num;
295 };
296 
297 static void cmd_port_host_shaper_parsed(void *parsed_result,
298 		__rte_unused struct cmdline *cl,
299 		__rte_unused void *data)
300 {
301 	struct cmd_port_host_shaper_result *res = parsed_result;
302 	int ret = 0;
303 
304 	if ((strcmp(res->mlx5, "mlx5") == 0) &&
305 	    (strcmp(res->set, "set") == 0) &&
306 	    (strcmp(res->port, "port") == 0) &&
307 	    (strcmp(res->host_shaper, "host_shaper") == 0) &&
308 	    (strcmp(res->avail_thresh_triggered, "avail_thresh_triggered") == 0) &&
309 	    (strcmp(res->rate, "rate") == 0))
310 		ret = mlx5_test_set_port_host_shaper(res->port_num, res->fr,
311 					   res->rate_num);
312 	if (ret < 0)
313 		printf("cmd_port_host_shaper error: (%s)\n", strerror(-ret));
314 }
315 
316 static cmdline_parse_token_string_t cmd_port_host_shaper_mlx5 =
317 	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
318 				mlx5, "mlx5");
319 static cmdline_parse_token_string_t cmd_port_host_shaper_set =
320 	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
321 				set, "set");
322 static cmdline_parse_token_string_t cmd_port_host_shaper_port =
323 	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
324 				port, "port");
325 static cmdline_parse_token_num_t cmd_port_host_shaper_portnum =
326 	TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
327 				port_num, RTE_UINT16);
328 static cmdline_parse_token_string_t cmd_port_host_shaper_host_shaper =
329 	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
330 				 host_shaper, "host_shaper");
331 static cmdline_parse_token_string_t cmd_port_host_shaper_avail_thresh_triggered =
332 	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
333 				 avail_thresh_triggered, "avail_thresh_triggered");
334 static cmdline_parse_token_num_t cmd_port_host_shaper_fr =
335 	TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
336 			      fr, RTE_UINT16);
337 static cmdline_parse_token_string_t cmd_port_host_shaper_rate =
338 	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
339 				 rate, "rate");
340 static cmdline_parse_token_num_t cmd_port_host_shaper_rate_num =
341 	TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
342 			      rate_num, RTE_UINT8);
343 static cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper = {
344 	.f = cmd_port_host_shaper_parsed,
345 	.data = (void *)0,
346 	.help_str = "mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> "
347 	"rate <rate_num>: Set HOST_SHAPER avail_thresh_triggered and rate with port_id",
348 	.tokens = {
349 		(void *)&cmd_port_host_shaper_mlx5,
350 		(void *)&cmd_port_host_shaper_set,
351 		(void *)&cmd_port_host_shaper_port,
352 		(void *)&cmd_port_host_shaper_portnum,
353 		(void *)&cmd_port_host_shaper_host_shaper,
354 		(void *)&cmd_port_host_shaper_avail_thresh_triggered,
355 		(void *)&cmd_port_host_shaper_fr,
356 		(void *)&cmd_port_host_shaper_rate,
357 		(void *)&cmd_port_host_shaper_rate_num,
358 		NULL,
359 	}
360 };
361 
362 #ifndef RTE_EXEC_ENV_WINDOWS
363 /* *** attach a specified port *** */
364 struct mlx5_cmd_operate_attach_port_result {
365 	cmdline_fixed_string_t mlx5;
366 	cmdline_fixed_string_t port;
367 	cmdline_fixed_string_t keyword;
368 	cmdline_multi_string_t identifier;
369 };
370 
371 static void mlx5_cmd_operate_attach_port_parsed(void *parsed_result,
372 						__rte_unused struct cmdline *cl,
373 						__rte_unused void *data)
374 {
375 	struct mlx5_cmd_operate_attach_port_result *res = parsed_result;
376 
377 	if (!strcmp(res->keyword, "attach"))
378 		mlx5_test_attach_port_extend_devargs(res->identifier);
379 	else
380 		fprintf(stderr, "Unknown parameter\n");
381 }
382 
383 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_mlx5 =
384 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
385 				 mlx5, "mlx5");
386 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_port =
387 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
388 				 port, "port");
389 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_keyword =
390 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
391 				 keyword, "attach");
392 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_identifier =
393 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
394 				 identifier, TOKEN_STRING_MULTI);
395 
396 static cmdline_parse_inst_t mlx5_cmd_operate_attach_port = {
397 	.f = mlx5_cmd_operate_attach_port_parsed,
398 	.data = NULL,
399 	.help_str = "mlx5 port attach <identifier> socket=<path>: "
400 		"(identifier: pci address or virtual dev name"
401 		", path (optional): socket path to get cmd FD and PD handle)",
402 	.tokens = {
403 		(void *)&mlx5_cmd_operate_attach_port_mlx5,
404 		(void *)&mlx5_cmd_operate_attach_port_port,
405 		(void *)&mlx5_cmd_operate_attach_port_keyword,
406 		(void *)&mlx5_cmd_operate_attach_port_identifier,
407 		NULL,
408 	},
409 };
410 #endif
411 
412 /* Map HW queue index to rte queue index. */
413 struct mlx5_cmd_map_ext_rxq {
414 	cmdline_fixed_string_t mlx5;
415 	cmdline_fixed_string_t port;
416 	portid_t port_id;
417 	cmdline_fixed_string_t ext_rxq;
418 	cmdline_fixed_string_t map;
419 	uint16_t sw_queue_id;
420 	uint32_t hw_queue_id;
421 };
422 
423 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_mlx5 =
424 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, mlx5, "mlx5");
425 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_port =
426 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port, "port");
427 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_port_id =
428 	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port_id, RTE_UINT16);
429 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_ext_rxq =
430 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, ext_rxq,
431 				 "ext_rxq");
432 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_map =
433 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, map, "map");
434 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_sw_queue_id =
435 	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, sw_queue_id,
436 			      RTE_UINT16);
437 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_hw_queue_id =
438 	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, hw_queue_id,
439 			      RTE_UINT32);
440 
441 static void
442 mlx5_cmd_map_ext_rxq_parsed(void *parsed_result,
443 			    __rte_unused struct cmdline *cl,
444 			    __rte_unused void *data)
445 {
446 	struct mlx5_cmd_map_ext_rxq *res = parsed_result;
447 	int ret;
448 
449 	if (port_id_is_invalid(res->port_id, ENABLED_WARN))
450 		return;
451 	ret = rte_pmd_mlx5_external_rx_queue_id_map(res->port_id,
452 						    res->sw_queue_id,
453 						    res->hw_queue_id);
454 	switch (ret) {
455 	case 0:
456 		break;
457 	case -EINVAL:
458 		fprintf(stderr, "invalid ethdev index (%u), out of range\n",
459 			res->sw_queue_id);
460 		break;
461 	case -ENODEV:
462 		fprintf(stderr, "invalid port_id %u\n", res->port_id);
463 		break;
464 	case -ENOTSUP:
465 		fprintf(stderr, "function not implemented or supported\n");
466 		break;
467 	case -EEXIST:
468 		fprintf(stderr, "mapping with index %u already exists\n",
469 			res->sw_queue_id);
470 		break;
471 	default:
472 		fprintf(stderr, "programming error: (%s)\n", strerror(-ret));
473 	}
474 }
475 
476 cmdline_parse_inst_t mlx5_cmd_map_ext_rxq = {
477 	.f = mlx5_cmd_map_ext_rxq_parsed,
478 	.data = NULL,
479 	.help_str = "mlx5 port <port_id> ext_rxq map <sw_queue_id> <hw_queue_id>",
480 	.tokens = {
481 		(void *)&mlx5_cmd_map_ext_rxq_mlx5,
482 		(void *)&mlx5_cmd_map_ext_rxq_port,
483 		(void *)&mlx5_cmd_map_ext_rxq_port_id,
484 		(void *)&mlx5_cmd_map_ext_rxq_ext_rxq,
485 		(void *)&mlx5_cmd_map_ext_rxq_map,
486 		(void *)&mlx5_cmd_map_ext_rxq_sw_queue_id,
487 		(void *)&mlx5_cmd_map_ext_rxq_hw_queue_id,
488 		NULL,
489 	}
490 };
491 
492 /* Unmap HW queue index to rte queue index. */
493 struct mlx5_cmd_unmap_ext_rxq {
494 	cmdline_fixed_string_t mlx5;
495 	cmdline_fixed_string_t port;
496 	portid_t port_id;
497 	cmdline_fixed_string_t ext_rxq;
498 	cmdline_fixed_string_t unmap;
499 	uint16_t queue_id;
500 };
501 
502 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_mlx5 =
503 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, mlx5, "mlx5");
504 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_port =
505 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port, "port");
506 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_port_id =
507 	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port_id,
508 			      RTE_UINT16);
509 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_ext_rxq =
510 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, ext_rxq,
511 				 "ext_rxq");
512 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_unmap =
513 	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, unmap, "unmap");
514 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_queue_id =
515 	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, queue_id,
516 			      RTE_UINT16);
517 
518 static void
519 mlx5_cmd_unmap_ext_rxq_parsed(void *parsed_result,
520 			      __rte_unused struct cmdline *cl,
521 			      __rte_unused void *data)
522 {
523 	struct mlx5_cmd_unmap_ext_rxq *res = parsed_result;
524 	int ret;
525 
526 	if (port_id_is_invalid(res->port_id, ENABLED_WARN))
527 		return;
528 	ret = rte_pmd_mlx5_external_rx_queue_id_unmap(res->port_id,
529 						      res->queue_id);
530 	switch (ret) {
531 	case 0:
532 		break;
533 	case -EINVAL:
534 		fprintf(stderr, "invalid rte_flow index (%u), "
535 			"out of range, doesn't exist or still referenced\n",
536 			res->queue_id);
537 		break;
538 	case -ENODEV:
539 		fprintf(stderr, "invalid port_id %u\n", res->port_id);
540 		break;
541 	case -ENOTSUP:
542 		fprintf(stderr, "function not implemented or supported\n");
543 		break;
544 	default:
545 		fprintf(stderr, "programming error: (%s)\n", strerror(-ret));
546 	}
547 }
548 
549 cmdline_parse_inst_t mlx5_cmd_unmap_ext_rxq = {
550 	.f = mlx5_cmd_unmap_ext_rxq_parsed,
551 	.data = NULL,
552 	.help_str = "mlx5 port <port_id> ext_rxq unmap <queue_id>",
553 	.tokens = {
554 		(void *)&mlx5_cmd_unmap_ext_rxq_mlx5,
555 		(void *)&mlx5_cmd_unmap_ext_rxq_port,
556 		(void *)&mlx5_cmd_unmap_ext_rxq_port_id,
557 		(void *)&mlx5_cmd_unmap_ext_rxq_ext_rxq,
558 		(void *)&mlx5_cmd_unmap_ext_rxq_unmap,
559 		(void *)&mlx5_cmd_unmap_ext_rxq_queue_id,
560 		NULL,
561 	}
562 };
563 
564 static struct testpmd_driver_commands mlx5_driver_cmds = {
565 	.commands = {
566 		{
567 			.ctx = &mlx5_test_cmd_port_host_shaper,
568 			.help = "mlx5 set port (port_id) host_shaper avail_thresh_triggered (on|off)"
569 				"rate (rate_num):\n"
570 				"    Set HOST_SHAPER avail_thresh_triggered and rate with port_id\n\n",
571 		},
572 #ifndef RTE_EXEC_ENV_WINDOWS
573 		{
574 			.ctx = &mlx5_cmd_operate_attach_port,
575 			.help = "mlx5 port attach (ident) socket=(path)\n"
576 				"    Attach physical or virtual dev by pci address or virtual device name "
577 				"and add \"cmd_fd\" and \"pd_handle\" devargs before attaching\n\n",
578 		},
579 #endif
580 		{
581 			.ctx = &mlx5_cmd_map_ext_rxq,
582 			.help = "mlx5 port (port_id) ext_rxq map (sw_queue_id) (hw_queue_id)\n"
583 				"    Map HW queue index (32-bit) to ethdev"
584 				" queue index (16-bit) for external RxQ\n\n",
585 		},
586 		{
587 			.ctx = &mlx5_cmd_unmap_ext_rxq,
588 			.help = "mlx5 port (port_id) ext_rxq unmap (sw_queue_id)\n"
589 				"    Unmap external Rx queue ethdev index mapping\n\n",
590 		},
591 		{
592 			.ctx = NULL,
593 		},
594 	}
595 };
596 TESTPMD_ADD_DRIVER_COMMANDS(mlx5_driver_cmds);
597