1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2021 6WIND S.A.
3 * Copyright 2021 Mellanox Technologies, Ltd
10 #ifndef RTE_EXEC_ENV_WINDOWS
11 #include <sys/socket.h>
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>
23 #include "mlx5_testpmd.h"
26 static uint8_t host_shaper_avail_thresh_triggered[RTE_MAX_ETHPORTS];
27 #define SHAPER_DISABLE_DELAY_US 100000 /* 100ms */
30 * Disable the host shaper and re-arm available descriptor threshold event.
33 * uint32_t integer combining port_id and rxq_id.
36 mlx5_test_host_shaper_disable(void *args)
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;
43 printf("%s disable shaper\n", __func__);
44 if (rte_eth_rx_queue_info_get(port_id, qid, &qinfo)) {
45 printf("rx_queue_info_get returns error\n");
48 /* Rearm the available descriptor threshold event. */
49 if (rte_eth_rx_avail_thresh_set(port_id, qid, qinfo.avail_thresh)) {
50 printf("config avail_thresh returns error\n");
53 /* Only disable the shaper when avail_thresh_triggered is set. */
54 if (host_shaper_avail_thresh_triggered[port_id] &&
55 rte_pmd_mlx5_host_shaper_config(port_id, 0, 0))
56 printf("%s disable shaper returns error\n", __func__);
60 mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id)
62 struct rte_eth_dev_info dev_info;
63 uint32_t port_rxq_id = port_id | (rxq_id << 16);
65 /* Ensure it's MLX5 port. */
66 if (rte_eth_dev_info_get(port_id, &dev_info) != 0 ||
67 (strncmp(dev_info.driver_name, "mlx5", 4) != 0))
69 rte_eal_alarm_set(SHAPER_DISABLE_DELAY_US,
70 mlx5_test_host_shaper_disable,
71 (void *)(uintptr_t)port_rxq_id);
72 printf("%s port_id:%u rxq_id:%u\n", __func__, port_id, rxq_id);
76 * Configure host shaper's avail_thresh_triggered and current rate.
78 * @param[in] avail_thresh_triggered
79 * Disable/enable avail_thresh_triggered.
81 * Configure current host shaper rate.
83 * On success, returns 0.
84 * On failure, returns < 0.
87 mlx5_test_set_port_host_shaper(uint16_t port_id, uint16_t avail_thresh_triggered, uint8_t rate)
89 struct rte_eth_link link;
90 bool port_id_valid = false;
94 RTE_ETH_FOREACH_DEV(pid)
101 ret = rte_eth_link_get_nowait(port_id, &link);
104 host_shaper_avail_thresh_triggered[port_id] = avail_thresh_triggered ? 1 : 0;
105 if (!avail_thresh_triggered) {
106 ret = rte_pmd_mlx5_host_shaper_config(port_id, 0,
107 RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED));
109 ret = rte_pmd_mlx5_host_shaper_config(port_id, 1,
110 RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED));
114 ret = rte_pmd_mlx5_host_shaper_config(port_id, rate, 0);
120 #ifndef RTE_EXEC_ENV_WINDOWS
122 mlx5_test_get_socket_path(char *extend)
124 if (strstr(extend, "socket=") == extend) {
125 const char *socket_path = strchr(extend, '=') + 1;
127 TESTPMD_LOG(DEBUG, "MLX5 socket path is %s\n", socket_path);
131 TESTPMD_LOG(ERR, "Failed to extract a valid socket path from %s\n",
137 mlx5_test_extend_devargs(char *identifier, char *extend)
139 struct sockaddr_un un = {
140 .sun_family = AF_UNIX,
145 .iov_base = &pd_handle,
146 .iov_len = sizeof(int),
149 char buf[CMSG_SPACE(sizeof(int))];
150 struct cmsghdr align;
152 struct msghdr msgh = {
156 struct cmsghdr *cmsg;
157 const char *path = mlx5_test_get_socket_path(extend + 1);
163 TESTPMD_LOG(ERR, "Invalid devargs extension is specified\n");
167 /* Initialize IPC channel. */
168 socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
170 TESTPMD_LOG(ERR, "Failed to create unix socket: %s\n",
174 rte_strlcpy(un.sun_path, path, sizeof(un.sun_path));
175 if (connect(socket_fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
176 TESTPMD_LOG(ERR, "Failed to connect %s: %s\n", un.sun_path,
182 /* Send the request message. */
184 ret = sendmsg(socket_fd, &msgh, 0);
185 } while (ret < 0 && errno == EINTR);
187 TESTPMD_LOG(ERR, "Failed to send request to (%s): %s\n", path,
195 msgh.msg_control = control.buf;
196 msgh.msg_controllen = sizeof(control.buf);
198 ret = recvmsg(socket_fd, &msgh, 0);
200 if (ret != sizeof(int) || (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
201 TESTPMD_LOG(ERR, "truncated msg");
206 /* Translate the FD. */
207 cmsg = CMSG_FIRSTHDR(&msgh);
208 if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
209 cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
210 TESTPMD_LOG(ERR, "Fail to get FD using SCM_RIGHTS mechanism\n");
215 memcpy(&cmd_fd, CMSG_DATA(cmsg), sizeof(int));
217 TESTPMD_LOG(DEBUG, "Command FD (%d) and PD handle (%d) "
218 "are successfully imported from remote process\n",
221 /* Cleanup IPC channel. */
224 /* Calculate the new length of devargs string. */
225 len += snprintf(NULL, 0, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle);
226 /* Extend the devargs string. */
227 snprintf(extend, len, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle);
229 TESTPMD_LOG(DEBUG, "Attach port with extra devargs %s\n", identifier);
234 is_delimiter_path_spaces(char *extend)
236 while (*extend != '\0') {
245 * Extend devargs list with "cmd_fd" and "pd_handle" coming from external
246 * process. It happens only in this format:
247 * testpmd> mlx5 port attach (identifier) socket=<socket path>
248 * all "(identifier) socket=<socket path>" is in the same string pointed
249 * by the input parameter 'identifier'.
252 * Identifier of port attach command line.
255 mlx5_test_attach_port_extend_devargs(char *identifier)
259 if (identifier == NULL) {
260 fprintf(stderr, "Invalid parameters are specified\n");
264 extend = strchr(identifier, ' ');
265 if (extend != NULL && is_delimiter_path_spaces(extend) &&
266 mlx5_test_extend_devargs(identifier, extend) < 0) {
267 TESTPMD_LOG(ERR, "Failed to extend devargs for port %s\n",
272 attach_port(identifier);
276 /* *** SET HOST_SHAPER FOR A PORT *** */
277 struct cmd_port_host_shaper_result {
278 cmdline_fixed_string_t mlx5;
279 cmdline_fixed_string_t set;
280 cmdline_fixed_string_t port;
282 cmdline_fixed_string_t host_shaper;
283 cmdline_fixed_string_t avail_thresh_triggered;
285 cmdline_fixed_string_t rate;
289 static void cmd_port_host_shaper_parsed(void *parsed_result,
290 __rte_unused struct cmdline *cl,
291 __rte_unused void *data)
293 struct cmd_port_host_shaper_result *res = parsed_result;
296 if ((strcmp(res->mlx5, "mlx5") == 0) &&
297 (strcmp(res->set, "set") == 0) &&
298 (strcmp(res->port, "port") == 0) &&
299 (strcmp(res->host_shaper, "host_shaper") == 0) &&
300 (strcmp(res->avail_thresh_triggered, "avail_thresh_triggered") == 0) &&
301 (strcmp(res->rate, "rate") == 0))
302 ret = mlx5_test_set_port_host_shaper(res->port_num, res->fr,
305 printf("cmd_port_host_shaper error: (%s)\n", strerror(-ret));
308 static cmdline_parse_token_string_t cmd_port_host_shaper_mlx5 =
309 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
311 static cmdline_parse_token_string_t cmd_port_host_shaper_set =
312 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
314 static cmdline_parse_token_string_t cmd_port_host_shaper_port =
315 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
317 static cmdline_parse_token_num_t cmd_port_host_shaper_portnum =
318 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
319 port_num, RTE_UINT16);
320 static cmdline_parse_token_string_t cmd_port_host_shaper_host_shaper =
321 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
322 host_shaper, "host_shaper");
323 static cmdline_parse_token_string_t cmd_port_host_shaper_avail_thresh_triggered =
324 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
325 avail_thresh_triggered, "avail_thresh_triggered");
326 static cmdline_parse_token_num_t cmd_port_host_shaper_fr =
327 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
329 static cmdline_parse_token_string_t cmd_port_host_shaper_rate =
330 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
332 static cmdline_parse_token_num_t cmd_port_host_shaper_rate_num =
333 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
334 rate_num, RTE_UINT8);
335 static cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper = {
336 .f = cmd_port_host_shaper_parsed,
338 .help_str = "mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> "
339 "rate <rate_num>: Set HOST_SHAPER avail_thresh_triggered and rate with port_id",
341 (void *)&cmd_port_host_shaper_mlx5,
342 (void *)&cmd_port_host_shaper_set,
343 (void *)&cmd_port_host_shaper_port,
344 (void *)&cmd_port_host_shaper_portnum,
345 (void *)&cmd_port_host_shaper_host_shaper,
346 (void *)&cmd_port_host_shaper_avail_thresh_triggered,
347 (void *)&cmd_port_host_shaper_fr,
348 (void *)&cmd_port_host_shaper_rate,
349 (void *)&cmd_port_host_shaper_rate_num,
354 #ifndef RTE_EXEC_ENV_WINDOWS
355 /* *** attach a specified port *** */
356 struct mlx5_cmd_operate_attach_port_result {
357 cmdline_fixed_string_t mlx5;
358 cmdline_fixed_string_t port;
359 cmdline_fixed_string_t keyword;
360 cmdline_multi_string_t identifier;
363 static void mlx5_cmd_operate_attach_port_parsed(void *parsed_result,
364 __rte_unused struct cmdline *cl,
365 __rte_unused void *data)
367 struct mlx5_cmd_operate_attach_port_result *res = parsed_result;
369 if (!strcmp(res->keyword, "attach"))
370 mlx5_test_attach_port_extend_devargs(res->identifier);
372 fprintf(stderr, "Unknown parameter\n");
375 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_mlx5 =
376 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
378 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_port =
379 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
381 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_keyword =
382 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
384 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_identifier =
385 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result,
386 identifier, TOKEN_STRING_MULTI);
388 static cmdline_parse_inst_t mlx5_cmd_operate_attach_port = {
389 .f = mlx5_cmd_operate_attach_port_parsed,
391 .help_str = "mlx5 port attach <identifier> socket=<path>: "
392 "(identifier: pci address or virtual dev name"
393 ", path (optional): socket path to get cmd FD and PD handle)",
395 (void *)&mlx5_cmd_operate_attach_port_mlx5,
396 (void *)&mlx5_cmd_operate_attach_port_port,
397 (void *)&mlx5_cmd_operate_attach_port_keyword,
398 (void *)&mlx5_cmd_operate_attach_port_identifier,
404 static struct testpmd_driver_commands mlx5_driver_cmds = {
407 .ctx = &mlx5_test_cmd_port_host_shaper,
408 .help = "mlx5 set port (port_id) host_shaper avail_thresh_triggered (on|off)"
410 " Set HOST_SHAPER avail_thresh_triggered and rate with port_id\n\n",
412 #ifndef RTE_EXEC_ENV_WINDOWS
414 .ctx = &mlx5_cmd_operate_attach_port,
415 .help = "mlx5 port attach (ident) socket=(path)\n"
416 " Attach physical or virtual dev by pci address or virtual device name "
417 "and add \"cmd_fd\" and \"pd_handle\" devargs before attaching\n\n",
425 TESTPMD_ADD_DRIVER_COMMANDS(mlx5_driver_cmds);