From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 20195A057D; Tue, 28 Jun 2022 16:58:56 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A9B2440A7A; Tue, 28 Jun 2022 16:58:55 +0200 (CEST) Received: from NAM11-BN8-obe.outbound.protection.outlook.com (mail-bn8nam11on2040.outbound.protection.outlook.com [40.107.236.40]) by mails.dpdk.org (Postfix) with ESMTP id 04CBE40A7A for ; Tue, 28 Jun 2022 16:58:53 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=lyI6Rj2xOqoJV8uAkojKaIApfUkB5WEgyj3QPNzicyJ9iJOVJ2X5pkLMREYN6/n+pdYxBRc2aVgDjmBs9XiGIweftmpGo2PKkuGK4oHwNHYmcQn15GVE6G+P7dVa9t7PR4MUj2lrPFCuyhxBks1QEqIoX5bdbWHamqodtCdlKrnUbfyVOgvDD/FNEZvSK6GkEM0qRKVQ4xlBSiv/Y6z1JKpZjmcV53/CcNJXD1pznZ/yGwRCgfSE5HGioomqfcSq8I+fNk1HmRbg0/VopccB/TVUwQRczhkqKYDdpNNhVIeiTaRufu37kUUflyFdu8emHDvvfaSU18vMj85up4QrRw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ff2Uo1zJt4FVpkXpmJWtrkmOXp8Fs+zfJ74Y5wzjifg=; b=mitcUvCAqppfzDY5eNDaV8zCTUe2rsjpCkbClxFcWwvJ5mwbFvjJcGTGSBcRsh/5pJ3w6NU9TiFdw9APh8VwkCMrHrRZOEwZEyE74w3dx2GaQDwyYsZXShupLwVChnG4tiqVp5bra3EGGtxKizHolgz4qzVobLODiMy32xjEsiPWWdSm/RP1MZgkR+i/FKUdeGBI2Kg+tXY/uRArmopAbUqPMRtwoGBhnb19o6h2Kj2dV0ZFf9/zFJhtuovwvOLVOU6LafofIvu6Jh+3rUaaZI5fKD0pA1wTQsvhbebkjpH8Qz/i5QajDvVE2yBXFDbgynluK8fGLjSge2vMCMYT/Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 12.22.5.234) smtp.rcpttodomain=monjalon.net smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ff2Uo1zJt4FVpkXpmJWtrkmOXp8Fs+zfJ74Y5wzjifg=; b=SjIGo0P+0tQFM3ElQExsNpRYpl02uML6ivOCrcyD0/SI2OmxdHhr7MxmR1VZnHLX0y7b9W19AuhsmPm9VCNb1793nTABZiMqJ2+3mQBZhubAT6IwwKmJPoGHS/M2HBZZUL5WAiDoWpWoyUoZFxdUehmyxpp++PdjAUhOCV6p7B6HfR0ES93rSjJckEQ7NL0WAgm7/1DCADlH7WD74ukbYDSh08kuerHscxT3uc00u+p1/mblsZBAmRideeaxwXvOh9tCK63nva+dcW5cE9ssv9vGUtxqI/YIneCeIQZwthNacPx6+XvH3FgT+Ho57S2c+ifPes/hH07Ifbzlm0mbWA== Received: from DS7PR05CA0063.namprd05.prod.outlook.com (2603:10b6:8:57::19) by BYAPR12MB4632.namprd12.prod.outlook.com (2603:10b6:a03:110::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5373.18; Tue, 28 Jun 2022 14:58:50 +0000 Received: from DM6NAM11FT026.eop-nam11.prod.protection.outlook.com (2603:10b6:8:57:cafe::e6) by DS7PR05CA0063.outlook.office365.com (2603:10b6:8:57::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5395.7 via Frontend Transport; Tue, 28 Jun 2022 14:58:49 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 12.22.5.234) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 12.22.5.234 as permitted sender) receiver=protection.outlook.com; client-ip=12.22.5.234; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (12.22.5.234) by DM6NAM11FT026.mail.protection.outlook.com (10.13.172.161) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.5373.15 via Frontend Transport; Tue, 28 Jun 2022 14:58:49 +0000 Received: from drhqmail201.nvidia.com (10.126.190.180) by DRHQMAIL101.nvidia.com (10.27.9.10) with Microsoft SMTP Server (TLS) id 15.0.1497.32; Tue, 28 Jun 2022 14:58:48 +0000 Received: from drhqmail201.nvidia.com (10.126.190.180) by drhqmail201.nvidia.com (10.126.190.180) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Tue, 28 Jun 2022 07:58:48 -0700 Received: from nvidia.com (10.127.8.13) by mail.nvidia.com (10.126.190.180) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26 via Frontend Transport; Tue, 28 Jun 2022 07:58:47 -0700 From: Michael Baum To: CC: Matan Azrad , Raslan Darawsheh , Viacheslav Ovsiienko , Thomas Monjalon Subject: [PATCH v3 1/2] net/mlx5: add test for remote PD and CTX Date: Tue, 28 Jun 2022 17:58:40 +0300 Message-ID: <20220628145841.3364471-2-michaelba@nvidia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220628145841.3364471-1-michaelba@nvidia.com> References: <20220616171017.2597941-1-michaelba@nvidia.com> <20220628145841.3364471-1-michaelba@nvidia.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: f20d8497-3d4d-4786-2144-08da5916b589 X-MS-TrafficTypeDiagnostic: BYAPR12MB4632:EE_ X-LD-Processed: 43083d15-7273-40c1-b7db-39efd9ccc17a,ExtAddr X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: KsmAZ+P2SN+6w86CJ9isTO5x3XPZPajOfFxHHPxXjD9UWARLmGR8DyiBSdZ8Z2H3jfZGeY2M6eKsl3zde+Hsy2bf2DeqJIB0LAlWyZzLESkhlv4CZW822CCEZbS4Tg28YtIV0P3cuTG33+2UXcex63YZB9/52MymA8KdP98h8tt1hI4DRY7Mo9KnDkZ93UdJIKcss5Wy3fuUt1inV4PU0/IQrJYQn2GSdsjWdkQUzA0Xd4566vYSi+K0y1O0i8eyf9P1rs5xmYnAWvslKJz/MRX0f0VlHzj34mMGLZxXVBQf95RZZh/tcKmEO9gXdeVa+Usl/S9jAnL8ltJyLfbJ2BT67qsB/bozXpOIXHmrmhBPxb/yUXYS5bb7uY6r2CbeS3M8YfiWJRSd3iiNddCpxlQ7OkxO9B8eSLdQZ2hAxvYkmeKDfR/ThfdLY2sZG+UWoOY5HG0HC6iergHhwZ36J0WGCRnRNG/nbH6mGcKo/A0hmIghqZQP1Fc7mR6/SEIM7EQ4h1Bgc7MjfXgk/bK+w03NDKukZ8R0oCdKU8prLp1iWkR/5GXDhMb3fpprbMU9FC4DdnmlypnX4Yx5xbz2Xm257gMGyhTjCYgfHJmVGKTHYWvlTFYKim9+7Ms3DrQVID0UPmILGAKKllAKkS62eIhI8vIYYRPOk+8hXVNJnyu+bw2lYixCbBN2pZe1tdjRtg8ykwaBpyJb8nqJiOTjlFcTJmGFrioMqX60Cdc3YS5gdYYfZJQYuNd0xo1EHa+1vwKUam3/X05yqvqaSk2cAXZitV0jKL7uhKDChW9kL/XqkRNauz7lsJiZMKshgesdrF0STaeZLhvIy7tWyXmYuZ+UZnPvDYamluzYyS7fuxe8JapsfE7a75eNNKfSuBXX+qERHCoFPvRbGbtBTXWfbRwHbLe+99LdDcMCb2MjjWc= X-Forefront-Antispam-Report: CIP:12.22.5.234; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:InfoNoRecords; CAT:NONE; SFS:(13230016)(4636009)(376002)(39860400002)(136003)(346002)(396003)(46966006)(40470700004)(36840700001)(81166007)(5660300002)(83380400001)(82310400005)(6286002)(47076005)(7696005)(82740400003)(6916009)(54906003)(30864003)(356005)(36860700001)(186003)(55016003)(336012)(2906002)(316002)(1076003)(426003)(86362001)(26005)(966005)(2616005)(70206006)(41300700001)(478600001)(4326008)(40480700001)(70586007)(8676002)(36756003)(6666004)(8936002)(40460700003)(36900700001); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Jun 2022 14:58:49.4599 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: f20d8497-3d4d-4786-2144-08da5916b589 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[12.22.5.234]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT026.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR12MB4632 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add mlx5 internal option in testpmd similar to run-time function "port attach" which adds another parameter named "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. These arguments was added in this commit [1]. The syntax is: testpmd > mlx5 port attach (identifier) socket=(path) Where "path" is the IPC socket path agreed on the remote process. [1] http://patches.dpdk.org/project/dpdk/patch/20220224232511.3238707-4-michaelba@nvidia.com/ Signed-off-by: Michael Baum Reviewed-by: Thomas Monjalon Acked-by: Matan Azrad --- doc/guides/nics/mlx5.rst | 47 +++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 2 + drivers/net/mlx5/mlx5_testpmd.c | 220 ++++++++++++++++++++ 3 files changed, 269 insertions(+) diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index bc2bd2c8a6..cd3a613640 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -1793,3 +1793,50 @@ and disables ``avail_thresh_triggered``. .. code-block:: console testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 50 + + +Testpmd +------- + +port attach with socket path +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to allocate a port with ``libibverbs`` from external application. +For importing the external port with extra device arguments, +there is a specific testpmd command +similar to :ref:`port attach command `:: + + testpmd> mlx5 port attach (identifier) socket=(path) + +where: + +* ``identifier``: device identifier with optional parameters + as same as :ref:`port attach command `. +* ``path``: path to IPC server socket created by the external application. + +This command performs: + +#. Open IPC client socket using the given path, and connect it. + +#. Import ibverbs context and ibverbs protection domain. + +#. Add two device arguments for context (``cmd_fd``) + and protection domain (``pd_handle``) to the device identifier. + See :ref:`mlx5 driver options ` for more + information about these device arguments. + +#. Call the regular ``port attach`` function with updated identifier. + +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> mlx5 port attach 0000:0a:00.0 socket=/var/run/import_ipc_socket + 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 + Attaching a new port... + EAL: Probe PCI driver: mlx5_pci (15b3:101d) device: 0000:0a:00.0 (socket 0) + Port 0 is attached. Now total ports is 1 + Done + diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index f716ea2797..c0965cd3b9 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -1882,6 +1882,8 @@ The following sections show functions for configuring ports. Port configuration changes only become active when forwarding is started/restarted. +.. _port_attach: + port attach ~~~~~~~~~~~ diff --git a/drivers/net/mlx5/mlx5_testpmd.c b/drivers/net/mlx5/mlx5_testpmd.c index 4f9826496d..463ee8e764 100644 --- a/drivers/net/mlx5/mlx5_testpmd.c +++ b/drivers/net/mlx5/mlx5_testpmd.c @@ -6,6 +6,11 @@ #include #include #include +#include +#ifndef RTE_EXEC_ENV_WINDOWS +#include +#include +#endif #include #include @@ -14,6 +19,7 @@ #include #include #include + #include "mlx5_testpmd.h" #include "testpmd.h" @@ -111,6 +117,162 @@ mlx5_test_set_port_host_shaper(uint16_t port_id, uint16_t avail_thresh_triggered return 0; } +#ifndef RTE_EXEC_ENV_WINDOWS +static const char* +mlx5_test_get_socket_path(char *extend) +{ + if (strstr(extend, "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 +mlx5_test_extend_devargs(char *identifier, char *extend) +{ + struct sockaddr_un un = { + .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_iov = NULL, + .msg_iovlen = 0, + }; + struct cmsghdr *cmsg; + const char *path = mlx5_test_get_socket_path(extend + 1); + size_t len = 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_SEQPACKET, 0); + if (socket_fd < 0) { + TESTPMD_LOG(ERR, "Failed to create unix socket: %s\n", + strerror(errno)); + return -1; + } + rte_strlcpy(un.sun_path, path, sizeof(un.sun_path)); + if (connect(socket_fd, (struct sockaddr *)&un, sizeof(un)) < 0) { + TESTPMD_LOG(ERR, "Failed to connect %s: %s\n", un.sun_path, + strerror(errno)); + close(socket_fd); + return -1; + } + + /* 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); + 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); + 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); + + /* Calculate the new length of devargs string. */ + len += snprintf(NULL, 0, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); + /* Extend the devargs string. */ + snprintf(extend, len, ",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; +} + +/* + * Extend devargs list with "cmd_fd" and "pd_handle" coming from external + * process. It happens only in this format: + * testpmd> mlx5 port attach (identifier) socket= + * all "(identifier) socket=" is in the same string pointed + * by the input parameter 'identifier'. + * + * @param identifier + * Identifier of port attach command line. + */ +static void +mlx5_test_attach_port_extend_devargs(char *identifier) +{ + char *extend; + + if (identifier == NULL) { + fprintf(stderr, "Invalid parameters are specified\n"); + return; + } + + extend = strchr(identifier, ' '); + if (extend != NULL && is_delimiter_path_spaces(extend) && + mlx5_test_extend_devargs(identifier, extend) < 0) { + TESTPMD_LOG(ERR, "Failed to extend devargs for port %s\n", + identifier); + return; + } + + attach_port(identifier); +} +#endif + /* *** SET HOST_SHAPER FOR A PORT *** */ struct cmd_port_host_shaper_result { cmdline_fixed_string_t mlx5; @@ -189,6 +351,56 @@ static cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper = { } }; +#ifndef RTE_EXEC_ENV_WINDOWS +/* *** attach a specified port *** */ +struct mlx5_cmd_operate_attach_port_result { + cmdline_fixed_string_t mlx5; + cmdline_fixed_string_t port; + cmdline_fixed_string_t keyword; + cmdline_multi_string_t identifier; +}; + +static void mlx5_cmd_operate_attach_port_parsed(void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + struct mlx5_cmd_operate_attach_port_result *res = parsed_result; + + if (!strcmp(res->keyword, "attach")) + mlx5_test_attach_port_extend_devargs(res->identifier); + else + fprintf(stderr, "Unknown parameter\n"); +} + +static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_mlx5 = + TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, + mlx5, "mlx5"); +static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_port = + TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, + port, "port"); +static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_keyword = + TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, + keyword, "attach"); +static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_identifier = + TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, + identifier, TOKEN_STRING_MULTI); + +static cmdline_parse_inst_t mlx5_cmd_operate_attach_port = { + .f = mlx5_cmd_operate_attach_port_parsed, + .data = NULL, + .help_str = "mlx5 port attach socket=: " + "(identifier: pci address or virtual dev name" + ", path (optional): socket path to get cmd FD and PD handle)", + .tokens = { + (void *)&mlx5_cmd_operate_attach_port_mlx5, + (void *)&mlx5_cmd_operate_attach_port_port, + (void *)&mlx5_cmd_operate_attach_port_keyword, + (void *)&mlx5_cmd_operate_attach_port_identifier, + NULL, + }, +}; +#endif + static struct testpmd_driver_commands mlx5_driver_cmds = { .commands = { { @@ -197,6 +409,14 @@ static struct testpmd_driver_commands mlx5_driver_cmds = { "rate (rate_num):\n" " Set HOST_SHAPER avail_thresh_triggered and rate with port_id\n\n", }, +#ifndef RTE_EXEC_ENV_WINDOWS + { + .ctx = &mlx5_cmd_operate_attach_port, + .help = "mlx5 port attach (ident) 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 { .ctx = NULL, }, -- 2.25.1