Add mlx5 internal option in testpmd run-time function "port attach" to add another parameter named "mlx5_socket" for attaching port and add 2 devargs before.
The arguments are "cmd_fd" and "pd_handle" using to import device created out of PMD. Testpmd application import it using IPC, and updates the devargs list before attaching. The syntax is: testpmd > port attach (identifier) mlx5_socket=(path) Where "path" is the IPC socket path agreed on the remote process. Signed-off-by: Michael Baum <michae...@nvidia.com> Acked-by: Matan Azrad <ma...@nvidia.com> --- app/test-pmd/cmdline.c | 14 +- app/test-pmd/meson.build | 3 + app/test-pmd/testpmd.c | 153 ++++++++++++++++++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 40 +++++ 4 files changed, 208 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 7ab0575e64..479e0290c4 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -773,6 +773,12 @@ static void cmd_help_long_parsed(void *parsed_result, "port attach (ident)\n" " Attach physical or virtual dev by pci address or virtual device name\n\n" +#ifdef RTE_NET_MLX5 + "port attach (ident) mlx5_socket=(path)\n" + " Attach physical or virtual dev by pci address or virtual device name " + "and add \"cmd_fd\" and \"pd_handle\" devargs before attaching\n\n" +#endif + "port detach (port_id)\n" " Detach physical or virtual dev by port_id\n\n" @@ -1379,8 +1385,12 @@ cmdline_parse_token_string_t cmd_operate_attach_port_identifier = cmdline_parse_inst_t cmd_operate_attach_port = { .f = cmd_operate_attach_port_parsed, .data = NULL, - .help_str = "port attach <identifier>: " - "(identifier: pci address or virtual dev name)", + .help_str = "port attach <identifier> mlx5_socket=<path>: " + "(identifier: pci address or virtual dev name" +#ifdef RTE_NET_MLX5 + ", path (optional): socket path to get cmd FD and PD handle" +#endif + ")", .tokens = { (void *)&cmd_operate_attach_port_port, (void *)&cmd_operate_attach_port_keyword, diff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build index 43130c8856..c4fd379e67 100644 --- a/app/test-pmd/meson.build +++ b/app/test-pmd/meson.build @@ -73,3 +73,6 @@ endif if dpdk_conf.has('RTE_NET_DPAA') deps += ['bus_dpaa', 'mempool_dpaa', 'net_dpaa'] endif +if dpdk_conf.has('RTE_NET_MLX5') + deps += 'net_mlx5' +endif diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index fe2ce19f99..7ec95e5ae4 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -11,6 +11,10 @@ #include <fcntl.h> #ifndef RTE_EXEC_ENV_WINDOWS #include <sys/mman.h> +#ifdef RTE_NET_MLX5 +#include <sys/socket.h> +#include <sys/un.h> +#endif #endif #include <sys/types.h> #include <errno.h> @@ -3200,11 +3204,150 @@ reset_port(portid_t pid) printf("Done\n"); } +#if defined(RTE_NET_MLX5) && !defined(RTE_EXEC_ENV_WINDOWS) +static const char* +get_socket_path(char *extend) +{ + if (strstr(extend, "mlx5_socket=") == extend) { + const char *socket_path = strchr(extend, '=') + 1; + + TESTPMD_LOG(DEBUG, "MLX5 socket path is %s\n", socket_path); + return socket_path; + } + + TESTPMD_LOG(ERR, "Failed to extract a valid socket path from %s\n", + extend); + return NULL; +} + +static int +attach_port_extend_devargs(char *identifier, char *extend) +{ + struct sockaddr_un un = { + .sun_family = AF_UNIX, + }; + struct sockaddr_un dst = { + .sun_family = AF_UNIX, + }; + int cmd_fd; + int pd_handle; + struct iovec iov = { + .iov_base = &pd_handle, + .iov_len = sizeof(int), + }; + union { + char buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr align; + } control; + struct msghdr msgh = { + .msg_name = &dst, + .msg_namelen = sizeof(dst), + .msg_iov = NULL, + .msg_iovlen = 0, + }; + struct cmsghdr *cmsg; + const char *path = get_socket_path(extend + 1); + size_t length = 1; + int socket_fd; + int ret; + + if (path == NULL) { + TESTPMD_LOG(ERR, "Invalid devargs extension is specified\n"); + return -1; + } + + /* Initialize IPC channel. */ + socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (socket_fd < 0) { + TESTPMD_LOG(ERR, "Failed to create unix socket: %s\n", + strerror(errno)); + return -1; + } + snprintf(un.sun_path, sizeof(un.sun_path), "%s_%d", path, getpid()); + unlink(un.sun_path); /* May still exist since last run */ + if (bind(socket_fd, (struct sockaddr *)&un, sizeof(un)) < 0) { + TESTPMD_LOG(ERR, "Failed to bind %s: %s\n", un.sun_path, + strerror(errno)); + close(socket_fd); + return -1; + } + + strlcpy(dst.sun_path, path, sizeof(dst.sun_path)); + /* Send the request message. */ + do { + ret = sendmsg(socket_fd, &msgh, 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + TESTPMD_LOG(ERR, "Failed to send request to (%s): %s\n", path, + strerror(errno)); + close(socket_fd); + unlink(un.sun_path); + return -1; + } + + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + msgh.msg_control = control.buf; + msgh.msg_controllen = sizeof(control.buf); + do { + ret = recvmsg(socket_fd, &msgh, 0); + } while (ret < 0); + if (ret != sizeof(int) || (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) { + TESTPMD_LOG(ERR, "truncated msg"); + close(socket_fd); + unlink(un.sun_path); + return -1; + } + + /* Translate the FD. */ + cmsg = CMSG_FIRSTHDR(&msgh); + if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || + cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + TESTPMD_LOG(ERR, "Fail to get FD using SCM_RIGHTS mechanism\n"); + close(socket_fd); + unlink(un.sun_path); + return -1; + } + memcpy(&cmd_fd, CMSG_DATA(cmsg), sizeof(int)); + + TESTPMD_LOG(DEBUG, "Command FD (%d) and PD handle (%d) " + "are successfully imported from remote process\n", + cmd_fd, pd_handle); + + /* Cleanup IPC channel. */ + close(socket_fd); + unlink(un.sun_path); + + /* Calculate the new length of devargs string. */ + length += snprintf(NULL, 0, ",cmd_fd=%d,pd_handle=%d", + cmd_fd, pd_handle); + /* Extend the devargs string. */ + snprintf(extend, length, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); + + TESTPMD_LOG(DEBUG, "Attach port with extra devargs %s\n", identifier); + return 0; +} + +static bool +is_delimiter_path_spaces(char *extend) +{ + while (*extend != '\0') { + if (*extend != ' ') + return true; + extend++; + } + return false; +} +#endif + void attach_port(char *identifier) { portid_t pi; struct rte_dev_iterator iterator; +#if defined(RTE_NET_MLX5) && !defined(RTE_EXEC_ENV_WINDOWS) + char *extend; +#endif printf("Attaching a new port...\n"); @@ -3213,6 +3356,16 @@ attach_port(char *identifier) return; } +#if defined(RTE_NET_MLX5) && !defined(RTE_EXEC_ENV_WINDOWS) + extend = strchr(identifier, ' '); + if (extend != NULL && is_delimiter_path_spaces(extend) && + attach_port_extend_devargs(identifier, extend) < 0) { + TESTPMD_LOG(ERR, "Failed to extend devargs for port %s\n", + identifier); + return; + } +#endif + if (rte_dev_probe(identifier) < 0) { TESTPMD_LOG(ERR, "Failed to attach port %s\n", identifier); return; diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index 1083c6d538..d6490947c4 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -2127,6 +2127,46 @@ the mode and slave parameters must be given. Done +port attach with mlx5 socket path +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +MLX5 internal option to attach a port specified by pci address or virtual device +args and add extra devargs to it, which is imported from external process:: + + testpmd> port attach (identifier) mlx5_socket=(path) + +where: + +* ``identifier``: pci address or virtual device args. +* ``path``: socket path to import arguments agreed by the external process. + +The mlx5 PMD enables to import CTX and PD created outside the PMD. +It gets as devargs the device's ``cmd_fd`` and ``pd_handle``, +then using those arguments to import objects. +See :ref:`mlx5 driver options <mlx5_common_driver_options>` for more information. + +When ``cmd_fd`` and ``pd_handle`` arguments are coming from another process, +the FD must be dup'd before being passed. +In this function, testpmd initializes IPC socket to get FD using SCM_RIGHTS. +It gets the external process socket path, then import the ``cmd_fd`` and +``pd_handle`` arguments and add them to devargs list. +After updating this, it calls the regular ``port attach`` function +with extended idevtifier. + +For example, to attach a port whose pci address is ``0000:0a:00.0`` and its +socket path is ``/var/run/import_ipc_socket``. + +.. code-block:: console + + testpmd> port attach 0000:0a:00.0 mlx5_socket=/var/run/import_ipc_socket + Attaching a new port... + testpmd: MLX5 socket path is /var/run/import_ipc_socket + testpmd: Attach port with extra devargs 0000:0a:00.0,cmd_fd=40,pd_handle=1 + EAL: Probe PCI driver: mlx5_pci (15b3:101d) device: 0000:03:00.0 (socket 0) + Port 0 is attached. Now total ports is 1 + Done + + port detach ~~~~~~~~~~~ -- 2.25.1