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