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 9335CA0C4E; Tue, 2 Nov 2021 09:54:56 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3031941137; Tue, 2 Nov 2021 09:54:21 +0100 (CET) Received: from NAM11-BN8-obe.outbound.protection.outlook.com (mail-bn8nam11on2061.outbound.protection.outlook.com [40.107.236.61]) by mails.dpdk.org (Postfix) with ESMTP id 487B341101 for ; Tue, 2 Nov 2021 09:54:19 +0100 (CET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GuuMyKyU20ABwjTsxoHLMZBxY+ow6Kn8OxWH+5fiCpsTOLbGRoCNY0i2xBZ5QJcg/X2nHGMtmQHhSMMqnqMnqh1pwoTw03hldEBvgE3Opa6QXZ4gGoGMtykJ5g2NoXokSsU9Y3B4L7LPr7a0MBSaSjc6F1vx1TFIymnXwHYfbc/hlaG2zvVygQGUJMmnbbLGgzqM3s6dCSJLJVa3HYLVt0W7fNSbhlV/EKiTrZEJ7p2t+cJh0AOMh9YbRRshrIJS+ZvG3SgP8xaPB5JZvpI1bVT3FcEHG1xNS//fp4g9yK5b+kGRVeo8LUieQrlI6LO8TVi7yyKYqWsZE/VCIxzfpw== 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=9avCuzHxZDxVBm2JycU7ZECp9ZmZZ62LKUMjOkrzlns=; b=bKe2h7iZ0ilmMHqQ+odwwFDn4Uwm4Ww+aev3YVM9hljmkgSUV+X6HBfE2MLMY+agJylrlLWI5cjta+GVgio4Yv6Mav2gcfBrTW//ye+OrDIaTrnYi+KozR45U05KeaBtMxVBS9K9uulW/1RTU0916mn1zvlL4c2rl5zQx/ZJMj0gQWwEvA2V+jBM2xM95dU2hP/4K9kGlixzc9SWpz21s4qkBVAm9TjgfmkvpyoS+fqzfw78TDWU3c3sbSs1enjrKgBKgAckEikBeRSmYY9YOMNNfaCxcbrhtC3H29dgWcLjuVSwjWdXegKyoAz3HbgU7ownnz1PFmPwq/6T0S0RRg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.112.34) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=quarantine sp=quarantine 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=9avCuzHxZDxVBm2JycU7ZECp9ZmZZ62LKUMjOkrzlns=; b=uT50Wzb8r216aDZsnMPw3ChDUmpih6KCvTgwDbDxICOP38BSkn0aR5Sd8Fa2Ay6/a2j19PAgoM+4Da22edwJKpN5HpW6+n7GwjYNpBL7a5bEPO9VpoueXyYUE9lyC+/IrzczYPPb4hYXf82x2UhbxHHRRHXy7haAqd54V2yCUBxF5DoHhWbxkHuQE5pXQ7J2aL4oscjctbAAFMvSp7RptDln0kRvL1EURtArXBrMLSra7IJkYo+uyb9MTOBSySCgX+U4spOmk2fUfZnYqDtCIgsAACrs1a6ASrWZ6wGmq0xA2uifZST0/NniMzoQn5zAAsNRtgEQrOEE3jpaCcmZfw== Received: from DM6PR21CA0030.namprd21.prod.outlook.com (2603:10b6:5:174::40) by BYAPR12MB3351.namprd12.prod.outlook.com (2603:10b6:a03:de::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4649.15; Tue, 2 Nov 2021 08:54:14 +0000 Received: from DM6NAM11FT014.eop-nam11.prod.protection.outlook.com (2603:10b6:5:174:cafe::f0) by DM6PR21CA0030.outlook.office365.com (2603:10b6:5:174::40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4690.0 via Frontend Transport; Tue, 2 Nov 2021 08:54:14 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.112.34) smtp.mailfrom=nvidia.com; dpdk.org; dkim=none (message not signed) header.d=none;dpdk.org; dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.112.34 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.112.34; helo=mail.nvidia.com; Received: from mail.nvidia.com (216.228.112.34) by DM6NAM11FT014.mail.protection.outlook.com (10.13.173.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.4649.14 via Frontend Transport; Tue, 2 Nov 2021 08:54:14 +0000 Received: from nvidia.com (172.20.187.5) by HQMAIL107.nvidia.com (172.20.187.13) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Tue, 2 Nov 2021 08:54:11 +0000 From: Gregory Etelson To: , , CC: Date: Tue, 2 Nov 2021 10:53:44 +0200 Message-ID: <20211102085347.20568-8-getelson@nvidia.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211102085347.20568-1-getelson@nvidia.com> References: <20211101091514.3891-1-getelson@nvidia.com> <20211102085347.20568-1-getelson@nvidia.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-Originating-IP: [172.20.187.5] X-ClientProxiedBy: HQMAIL105.nvidia.com (172.20.187.12) To HQMAIL107.nvidia.com (172.20.187.13) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 5b82a148-3812-4576-3aeb-08d99dde5894 X-MS-TrafficTypeDiagnostic: BYAPR12MB3351: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:8882; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 2GDzZqW67Jxb+X7H71S8w89z0+mQcLvfq9CTQG+VMQn1XJnrbCpP1fPq58qyeJvoCZPOnWbjOGjmmYJW9Rm22TYvbuVGo3LBmWat4DG5IjVtVxYTZ/oqj/WGC5JnngIB+ndE7WmHpzT5XspllI2Ozm+1w3m8FDrG1s+ClVc0inRjht+NSHwwWK8B3+WvhWbS71IrcibLtD8yWPsvia0r55poguffM8Vjiqdb9OBvXoW5pdOpk9hHzbVblUMICL8X/j3a2N/EHvtObzC7DaHPXbztqnUnH9JmJ2BREi0jz7T40wyhp2uMcY6l2jL1W84b6pfV9kfP0NUlUrWMuK02SZmRg/EzR9msTTKlOAgacqGdCgjsdjDCOLEnvODjb9eFACaqGixCMde6z8/CIu4cmrhjus62Qq6olSrbfhXoLJzZBhust8EcZchPIbBSVgdxLMD+YnJGeFb8q1YdnI1RNQnM0P4zTX9CjXxQy9Go/CE4+/KBMe4qxkQntK6kzexYYwf3ZJK9JepLWvDhvAXK92VWwnGVLuDQ/gcF7T7rEjYpchP/91jpwfrp8O4lIvLO5u1xjTt9bE1T4gpv8ZIDmhnbIuj7TPPIsZcv01WM4+KX3BGPfuYj6ZvbmbPvQcdSmmh2EeUIHoahcflyNOZlSn+kCA1KY3cBJ/I71v2HXS+OAKfbUd1IAfS78y9yrAMjmfrNEVH5bM0xhWnEUAAKM60l8OGrLtM6LN1X+8OoTc4= X-Forefront-Antispam-Report: CIP:216.228.112.34; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:schybrid03.nvidia.com; CAT:NONE; SFS:(4636009)(46966006)(36840700001)(2906002)(55016002)(110136005)(82310400003)(5660300002)(83380400001)(6636002)(316002)(426003)(36860700001)(6286002)(2616005)(1076003)(186003)(16526019)(36756003)(8936002)(70586007)(8676002)(6666004)(7636003)(336012)(356005)(30864003)(26005)(86362001)(47076005)(4326008)(7696005)(508600001)(70206006)(107886003)(66574015)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Nov 2021 08:54:14.2866 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 5b82a148-3812-4576-3aeb-08d99dde5894 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.112.34]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT014.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR12MB3351 Subject: [dpdk-dev] [PATCH v2 7/9] net/mlx5: translate flex item configuration 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 Sender: "dev" From: Viacheslav Ovsiienko RTE Flow flex item configuration should be translated into actual hardware settings: - translate header length and next protocol field samplings - translate data field sampling, the similar fields with the same mode and matching related parameters are relocated and grouped to be covered with minimal amount of hardware sampling registers (each register can cover arbitrary neighbour 32 bits (aligned to byte boundary) in the packet and we can combine the fields with smaller lengths or segments of bigger fields) - input and output links translation - preparing data for parsing flex item pattern on flow creation Signed-off-by: Gregory Etelson Signed-off-by: Viacheslav Ovsiienko --- drivers/net/mlx5/mlx5.h | 15 + drivers/net/mlx5/mlx5_flow_flex.c | 844 +++++++++++++++++++++++++++++- 2 files changed, 858 insertions(+), 1 deletion(-) diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 63de6523e8..18dfa2fc7b 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -53,6 +53,9 @@ /* Maximal number of flex items created on the port.*/ #define MLX5_PORT_FLEX_ITEM_NUM 4 +/* Maximal number of field/field parts to map into sample registers .*/ +#define MLX5_FLEX_ITEM_MAPPING_NUM 32 + enum mlx5_ipool_index { #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) MLX5_IPOOL_DECAP_ENCAP = 0, /* Pool for encap/decap resource. */ @@ -1108,10 +1111,22 @@ struct mlx5_flex_parser_devx { uint32_t sample_ids[MLX5_GRAPH_NODE_SAMPLE_NUM]; }; +/* Pattern field dscriptor - how to translate flex pattern into samples. */ +__extension__ +struct mlx5_flex_pattern_field { + uint16_t width:6; + uint16_t shift:5; + uint16_t reg_id:5; +}; +#define MLX5_INVALID_SAMPLE_REG_ID 0x1F + /* Port flex item context. */ struct mlx5_flex_item { struct mlx5_flex_parser_devx *devx_fp; /* DevX flex parser object. */ uint32_t refcnt; /* Atomically accessed refcnt by flows. */ + enum rte_flow_item_flex_tunnel_mode tunnel_mode; /* Tunnel mode. */ + uint32_t mapnum; /* Number of pattern translation entries. */ + struct mlx5_flex_pattern_field map[MLX5_FLEX_ITEM_MAPPING_NUM]; }; /* diff --git a/drivers/net/mlx5/mlx5_flow_flex.c b/drivers/net/mlx5/mlx5_flow_flex.c index 2f87073e97..b4a9f1a537 100644 --- a/drivers/net/mlx5/mlx5_flow_flex.c +++ b/drivers/net/mlx5/mlx5_flow_flex.c @@ -113,6 +113,847 @@ mlx5_flex_free(struct mlx5_priv *priv, struct mlx5_flex_item *item) } } +/* + * Calculate largest mask value for a given shift. + * + * shift mask + * ------- --------------- + * 0 b111100 0x3C + * 1 b111110 0x3E + * 2 b111111 0x3F + * 3 b011111 0x1F + * 4 b001111 0x0F + * 5 b000111 0x07 + */ +static uint8_t +mlx5_flex_hdr_len_mask(uint8_t shift, + const struct mlx5_hca_flex_attr *attr) +{ + uint32_t base_mask; + int diff = shift - MLX5_PARSE_GRAPH_NODE_HDR_LEN_SHIFT_DWORD; + + base_mask = mlx5_hca_parse_graph_node_base_hdr_len_mask(attr); + return diff == 0 ? base_mask : + diff < 0 ? (base_mask << -diff) & base_mask : base_mask >> diff; +} + +static int +mlx5_flex_translate_length(struct mlx5_hca_flex_attr *attr, + const struct rte_flow_item_flex_conf *conf, + struct mlx5_flex_parser_devx *devx, + struct rte_flow_error *error) +{ + const struct rte_flow_item_flex_field *field = &conf->next_header; + struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; + uint32_t len_width, mask; + + if (field->field_base % CHAR_BIT) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "not byte aligned header length field"); + switch (field->field_mode) { + case FIELD_MODE_DUMMY: + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "invalid header length field mode (DUMMY)"); + case FIELD_MODE_FIXED: + if (!(attr->header_length_mode & + RTE_BIT32(MLX5_GRAPH_NODE_LEN_FIXED))) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported header length field mode (FIXED)"); + if (attr->header_length_mask_width < field->field_size) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "header length field width exceeds limit"); + if (field->offset_shift < 0 || + field->offset_shift > attr->header_length_mask_width) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "invalid header length field shift (FIXED"); + if (field->field_base < 0) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "negative header length field base (FIXED)"); + node->header_length_mode = MLX5_GRAPH_NODE_LEN_FIXED; + break; + case FIELD_MODE_OFFSET: + if (!(attr->header_length_mode & + RTE_BIT32(MLX5_GRAPH_NODE_LEN_FIELD))) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported header length field mode (OFFSET)"); + node->header_length_mode = MLX5_GRAPH_NODE_LEN_FIELD; + if (field->offset_mask == 0 || + !rte_is_power_of_2(field->offset_mask + 1)) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "invalid length field offset mask (OFFSET)"); + len_width = rte_fls_u32(field->offset_mask); + if (len_width > attr->header_length_mask_width) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "length field offset mask too wide (OFFSET)"); + mask = mlx5_flex_hdr_len_mask(field->offset_shift, attr); + if (mask < field->offset_mask) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "length field shift too big (OFFSET)"); + node->header_length_field_mask = RTE_MIN(mask, + field->offset_mask); + break; + case FIELD_MODE_BITMASK: + if (!(attr->header_length_mode & + RTE_BIT32(MLX5_GRAPH_NODE_LEN_BITMASK))) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported header length field mode (BITMASK)"); + if (attr->header_length_mask_width < field->field_size) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "header length field width exceeds limit"); + node->header_length_mode = MLX5_GRAPH_NODE_LEN_BITMASK; + mask = mlx5_flex_hdr_len_mask(field->offset_shift, attr); + if (mask < field->offset_mask) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "length field shift too big (BITMASK)"); + node->header_length_field_mask = RTE_MIN(mask, + field->offset_mask); + break; + default: + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unknown header length field mode"); + } + if (field->field_base / CHAR_BIT >= 0 && + field->field_base / CHAR_BIT > attr->max_base_header_length) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "header length field base exceeds limit"); + node->header_length_base_value = field->field_base / CHAR_BIT; + if (field->field_mode == FIELD_MODE_OFFSET || + field->field_mode == FIELD_MODE_BITMASK) { + if (field->offset_shift > 15 || field->offset_shift < 0) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "header length field shift exceeeds limit"); + node->header_length_field_shift = field->offset_shift; + node->header_length_field_offset = field->offset_base; + } + return 0; +} + +static int +mlx5_flex_translate_next(struct mlx5_hca_flex_attr *attr, + const struct rte_flow_item_flex_conf *conf, + struct mlx5_flex_parser_devx *devx, + struct rte_flow_error *error) +{ + const struct rte_flow_item_flex_field *field = &conf->next_protocol; + struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; + + switch (field->field_mode) { + case FIELD_MODE_DUMMY: + if (conf->nb_outputs) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "next protocol field is required (DUMMY)"); + return 0; + case FIELD_MODE_FIXED: + break; + case FIELD_MODE_OFFSET: + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported next protocol field mode (OFFSET)"); + break; + case FIELD_MODE_BITMASK: + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported next protocol field mode (BITMASK)"); + default: + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unknown next protocol field mode"); + } + MLX5_ASSERT(field->field_mode == FIELD_MODE_FIXED); + if (!conf->nb_outputs) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "out link(s) is required if next field present"); + if (attr->max_next_header_offset < field->field_base) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "next protocol field base exceeds limit"); + if (field->offset_shift) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported next protocol field shift"); + node->next_header_field_offset = field->field_base; + node->next_header_field_size = field->field_size; + return 0; +} + +/* Helper structure to handle field bit intervals. */ +struct mlx5_flex_field_cover { + uint16_t num; + int32_t start[MLX5_FLEX_ITEM_MAPPING_NUM]; + int32_t end[MLX5_FLEX_ITEM_MAPPING_NUM]; + uint8_t mapped[MLX5_FLEX_ITEM_MAPPING_NUM / CHAR_BIT + 1]; +}; + +static void +mlx5_flex_insert_field(struct mlx5_flex_field_cover *cover, + uint16_t num, int32_t start, int32_t end) +{ + MLX5_ASSERT(num < MLX5_FLEX_ITEM_MAPPING_NUM); + MLX5_ASSERT(num <= cover->num); + if (num < cover->num) { + memmove(&cover->start[num + 1], &cover->start[num], + (cover->num - num) * sizeof(int32_t)); + memmove(&cover->end[num + 1], &cover->end[num], + (cover->num - num) * sizeof(int32_t)); + } + cover->start[num] = start; + cover->end[num] = end; + cover->num++; +} + +static void +mlx5_flex_merge_field(struct mlx5_flex_field_cover *cover, uint16_t num) +{ + uint32_t i, del = 0; + int32_t end; + + MLX5_ASSERT(num < MLX5_FLEX_ITEM_MAPPING_NUM); + MLX5_ASSERT(num < (cover->num - 1)); + end = cover->end[num]; + for (i = num + 1; i < cover->num; i++) { + if (end < cover->start[i]) + break; + del++; + if (end <= cover->end[i]) { + cover->end[num] = cover->end[i]; + break; + } + } + if (del) { + MLX5_ASSERT(del < (cover->num - 1u - num)); + cover->num -= del; + MLX5_ASSERT(cover->num > num); + if ((cover->num - num) > 1) { + memmove(&cover->start[num + 1], + &cover->start[num + 1 + del], + (cover->num - num - 1) * sizeof(int32_t)); + memmove(&cover->end[num + 1], + &cover->end[num + 1 + del], + (cover->num - num - 1) * sizeof(int32_t)); + } + } +} + +/* + * Validate the sample field and update interval array + * if parameters match with the 'match" field. + * Returns: + * < 0 - error + * == 0 - no match, interval array not updated + * > 0 - match, interval array updated + */ +static int +mlx5_flex_cover_sample(struct mlx5_flex_field_cover *cover, + struct rte_flow_item_flex_field *field, + struct rte_flow_item_flex_field *match, + struct mlx5_hca_flex_attr *attr, + struct rte_flow_error *error) +{ + int32_t start, end; + uint32_t i; + + switch (field->field_mode) { + case FIELD_MODE_DUMMY: + return 0; + case FIELD_MODE_FIXED: + if (!(attr->sample_offset_mode & + RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_FIXED))) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported sample field mode (FIXED)"); + if (field->offset_shift) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "invalid sample field shift (FIXED"); + if (field->field_base < 0) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "invalid sample field base (FIXED)"); + if (field->field_base / CHAR_BIT > attr->max_sample_base_offset) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "sample field base exceeds limit (FIXED)"); + break; + case FIELD_MODE_OFFSET: + if (!(attr->sample_offset_mode & + RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_FIELD))) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported sample field mode (OFFSET)"); + if (field->field_base / CHAR_BIT >= 0 && + field->field_base / CHAR_BIT > attr->max_sample_base_offset) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "sample field base exceeds limit"); + break; + case FIELD_MODE_BITMASK: + if (!(attr->sample_offset_mode & + RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_BITMASK))) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported sample field mode (BITMASK)"); + if (field->field_base / CHAR_BIT >= 0 && + field->field_base / CHAR_BIT > attr->max_sample_base_offset) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "sample field base exceeds limit"); + break; + default: + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unknown data sample field mode"); + } + if (!match) { + if (!field->field_size) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "zero sample field width"); + if (field->field_id) + DRV_LOG(DEBUG, "sample field id hint ignored"); + } else { + if (field->field_mode != match->field_mode || + field->offset_base | match->offset_base || + field->offset_mask | match->offset_mask || + field->offset_shift | match->offset_shift) + return 0; + } + start = field->field_base; + end = start + field->field_size; + /* Add the new or similar field to interval array. */ + if (!cover->num) { + cover->start[cover->num] = start; + cover->end[cover->num] = end; + cover->num = 1; + return 1; + } + for (i = 0; i < cover->num; i++) { + if (start > cover->end[i]) { + if (i >= (cover->num - 1u)) { + mlx5_flex_insert_field(cover, cover->num, + start, end); + break; + } + continue; + } + if (end < cover->start[i]) { + mlx5_flex_insert_field(cover, i, start, end); + break; + } + if (start < cover->start[i]) + cover->start[i] = start; + if (end > cover->end[i]) { + cover->end[i] = end; + if (i < (cover->num - 1u)) + mlx5_flex_merge_field(cover, i); + } + break; + } + return 1; +} + +static void +mlx5_flex_config_sample(struct mlx5_devx_match_sample_attr *na, + struct rte_flow_item_flex_field *field, + enum rte_flow_item_flex_tunnel_mode tunnel_mode) +{ + memset(na, 0, sizeof(struct mlx5_devx_match_sample_attr)); + na->flow_match_sample_en = 1; + switch (field->field_mode) { + case FIELD_MODE_FIXED: + na->flow_match_sample_offset_mode = + MLX5_GRAPH_SAMPLE_OFFSET_FIXED; + break; + case FIELD_MODE_OFFSET: + na->flow_match_sample_offset_mode = + MLX5_GRAPH_SAMPLE_OFFSET_FIELD; + na->flow_match_sample_field_offset = field->offset_base; + na->flow_match_sample_field_offset_mask = field->offset_mask; + na->flow_match_sample_field_offset_shift = field->offset_shift; + break; + case FIELD_MODE_BITMASK: + na->flow_match_sample_offset_mode = + MLX5_GRAPH_SAMPLE_OFFSET_BITMASK; + na->flow_match_sample_field_offset = field->offset_base; + na->flow_match_sample_field_offset_mask = field->offset_mask; + na->flow_match_sample_field_offset_shift = field->offset_shift; + break; + default: + MLX5_ASSERT(false); + break; + } + switch (tunnel_mode) { + case FLEX_TUNNEL_MODE_SINGLE: + /* Fallthrough */ + case FLEX_TUNNEL_MODE_TUNNEL: + na->flow_match_sample_tunnel_mode = + MLX5_GRAPH_SAMPLE_TUNNEL_FIRST; + break; + case FLEX_TUNNEL_MODE_MULTI: + /* Fallthrough */ + case FLEX_TUNNEL_MODE_OUTER: + na->flow_match_sample_tunnel_mode = + MLX5_GRAPH_SAMPLE_TUNNEL_OUTER; + break; + case FLEX_TUNNEL_MODE_INNER: + na->flow_match_sample_tunnel_mode = + MLX5_GRAPH_SAMPLE_TUNNEL_INNER; + break; + default: + MLX5_ASSERT(false); + break; + } +} + +/* Map specified field to set/subset of allocated sample registers. */ +static int +mlx5_flex_map_sample(struct rte_flow_item_flex_field *field, + struct mlx5_flex_parser_devx *parser, + struct mlx5_flex_item *item, + struct rte_flow_error *error) +{ + struct mlx5_devx_match_sample_attr node; + int32_t start = field->field_base; + int32_t end = start + field->field_size; + struct mlx5_flex_pattern_field *trans; + uint32_t i, done_bits = 0; + + if (field->field_mode == FIELD_MODE_DUMMY) { + done_bits = field->field_size; + while (done_bits) { + uint32_t part = RTE_MIN(done_bits, + sizeof(uint32_t) * CHAR_BIT); + if (item->mapnum >= MLX5_FLEX_ITEM_MAPPING_NUM) + return rte_flow_error_set + (error, + EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "too many flex item pattern translations"); + trans = &item->map[item->mapnum]; + trans->reg_id = MLX5_INVALID_SAMPLE_REG_ID; + trans->shift = 0; + trans->width = part; + item->mapnum++; + done_bits -= part; + } + return 0; + } + mlx5_flex_config_sample(&node, field, item->tunnel_mode); + for (i = 0; i < parser->num_samples; i++) { + struct mlx5_devx_match_sample_attr *sample = + &parser->devx_conf.sample[i]; + int32_t reg_start, reg_end; + int32_t cov_start, cov_end; + + MLX5_ASSERT(sample->flow_match_sample_en); + if (!sample->flow_match_sample_en) + break; + node.flow_match_sample_field_base_offset = + sample->flow_match_sample_field_base_offset; + if (memcmp(&node, sample, sizeof(node))) + continue; + reg_start = (int8_t)sample->flow_match_sample_field_base_offset; + reg_start *= CHAR_BIT; + reg_end = reg_start + 32; + if (end <= reg_start || start >= reg_end) + continue; + cov_start = RTE_MAX(reg_start, start); + cov_end = RTE_MIN(reg_end, end); + MLX5_ASSERT(cov_end > cov_start); + done_bits += cov_end - cov_start; + if (item->mapnum >= MLX5_FLEX_ITEM_MAPPING_NUM) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "too many flex item pattern translations"); + trans = &item->map[item->mapnum]; + item->mapnum++; + trans->reg_id = i; + trans->shift = cov_start - reg_start; + trans->width = cov_end - cov_start; + } + if (done_bits != field->field_size) { + MLX5_ASSERT(false); + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "failed to map field to sample register"); + } + return 0; +} + +/* Allocate sample registers for the specified field type and interval array. */ +static int +mlx5_flex_alloc_sample(struct mlx5_flex_field_cover *cover, + struct mlx5_flex_parser_devx *parser, + struct mlx5_flex_item *item, + struct rte_flow_item_flex_field *field, + struct mlx5_hca_flex_attr *attr, + struct rte_flow_error *error) +{ + struct mlx5_devx_match_sample_attr node; + uint32_t idx = 0; + + mlx5_flex_config_sample(&node, field, item->tunnel_mode); + while (idx < cover->num) { + int32_t start, end; + + /* + * Sample base offsets are in bytes, should be aligned + * to 32-bit as required by firmware for samples. + */ + start = RTE_ALIGN_FLOOR(cover->start[idx], + sizeof(uint32_t) * CHAR_BIT); + node.flow_match_sample_field_base_offset = + (start / CHAR_BIT) & 0xFF; + /* Allocate sample register. */ + if (parser->num_samples >= MLX5_GRAPH_NODE_SAMPLE_NUM || + parser->num_samples >= attr->max_num_sample || + parser->num_samples >= attr->max_num_prog_sample) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "no sample registers to handle all flex item fields"); + parser->devx_conf.sample[parser->num_samples] = node; + parser->num_samples++; + /* Remove or update covered intervals. */ + end = start + 32; + while (idx < cover->num) { + if (end >= cover->end[idx]) { + idx++; + continue; + } + if (end > cover->start[idx]) + cover->start[idx] = end; + break; + } + } + return 0; +} + +static int +mlx5_flex_translate_sample(struct mlx5_hca_flex_attr *attr, + const struct rte_flow_item_flex_conf *conf, + struct mlx5_flex_parser_devx *parser, + struct mlx5_flex_item *item, + struct rte_flow_error *error) +{ + struct mlx5_flex_field_cover cover; + uint32_t i, j; + int ret; + + switch (conf->tunnel) { + case FLEX_TUNNEL_MODE_SINGLE: + /* Fallthrough */ + case FLEX_TUNNEL_MODE_OUTER: + /* Fallthrough */ + case FLEX_TUNNEL_MODE_INNER: + /* Fallthrough */ + case FLEX_TUNNEL_MODE_MULTI: + /* Fallthrough */ + case FLEX_TUNNEL_MODE_TUNNEL: + break; + default: + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unrecognized tunnel mode"); + } + item->tunnel_mode = conf->tunnel; + if (conf->nb_samples > MLX5_FLEX_ITEM_MAPPING_NUM) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "sample field number exceeds limit"); + /* + * The application can specify fields smaller or bigger than 32 bits + * covered with single sample register and it can specify field + * offsets in any order. + * + * Gather all similar fields together, build array of bit intervals + * in asсending order and try to cover with the smallest set of sample + * registers. + */ + memset(&cover, 0, sizeof(cover)); + for (i = 0; i < conf->nb_samples; i++) { + struct rte_flow_item_flex_field *fl = conf->sample_data + i; + + /* Check whether field was covered in the previous iteration. */ + if (cover.mapped[i / CHAR_BIT] & (1u << (i % CHAR_BIT))) + continue; + if (fl->field_mode == FIELD_MODE_DUMMY) + continue; + /* Build an interval array for the field and similar ones */ + cover.num = 0; + /* Add the first field to array unconditionally. */ + ret = mlx5_flex_cover_sample(&cover, fl, NULL, attr, error); + if (ret < 0) + return ret; + MLX5_ASSERT(ret > 0); + cover.mapped[i / CHAR_BIT] |= 1u << (i % CHAR_BIT); + for (j = i + 1; j < conf->nb_samples; j++) { + struct rte_flow_item_flex_field *ft; + + /* Add field to array if its type matches. */ + ft = conf->sample_data + j; + ret = mlx5_flex_cover_sample(&cover, ft, fl, + attr, error); + if (ret < 0) + return ret; + if (!ret) + continue; + cover.mapped[j / CHAR_BIT] |= 1u << (j % CHAR_BIT); + } + /* Allocate sample registers to cover array of intervals. */ + ret = mlx5_flex_alloc_sample(&cover, parser, item, + fl, attr, error); + if (ret) + return ret; + } + /* Build the item pattern translating data on flow creation. */ + item->mapnum = 0; + memset(&item->map, 0, sizeof(item->map)); + for (i = 0; i < conf->nb_samples; i++) { + struct rte_flow_item_flex_field *fl = conf->sample_data + i; + + ret = mlx5_flex_map_sample(fl, parser, item, error); + if (ret) { + MLX5_ASSERT(false); + return ret; + } + } + if (conf->tunnel == FLEX_TUNNEL_MODE_MULTI) { + /* + * In FLEX_TUNNEL_MODE_MULTI tunnel mode PMD creates 2 sets + * of samples. The first set is for outer and the second set + * for inner flex flow item. Outer and inner samples differ + * only in tunnel_mode. + */ + if (parser->num_samples > MLX5_GRAPH_NODE_SAMPLE_NUM / 2) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "no sample registers for inner"); + rte_memcpy(parser->devx_conf.sample + parser->num_samples, + parser->devx_conf.sample, + parser->num_samples * + sizeof(parser->devx_conf.sample[0])); + for (i = 0; i < parser->num_samples; i++) { + struct mlx5_devx_match_sample_attr *sm = i + + parser->devx_conf.sample + parser->num_samples; + + sm->flow_match_sample_tunnel_mode = + MLX5_GRAPH_SAMPLE_TUNNEL_INNER; + } + parser->num_samples *= 2; + } + return 0; +} + +static int +mlx5_flex_arc_type(enum rte_flow_item_type type, int in) +{ + switch (type) { + case RTE_FLOW_ITEM_TYPE_ETH: + return MLX5_GRAPH_ARC_NODE_MAC; + case RTE_FLOW_ITEM_TYPE_IPV4: + return in ? MLX5_GRAPH_ARC_NODE_IP : MLX5_GRAPH_ARC_NODE_IPV4; + case RTE_FLOW_ITEM_TYPE_IPV6: + return in ? MLX5_GRAPH_ARC_NODE_IP : MLX5_GRAPH_ARC_NODE_IPV6; + case RTE_FLOW_ITEM_TYPE_UDP: + return MLX5_GRAPH_ARC_NODE_UDP; + case RTE_FLOW_ITEM_TYPE_TCP: + return MLX5_GRAPH_ARC_NODE_TCP; + case RTE_FLOW_ITEM_TYPE_MPLS: + return MLX5_GRAPH_ARC_NODE_MPLS; + case RTE_FLOW_ITEM_TYPE_GRE: + return MLX5_GRAPH_ARC_NODE_GRE; + case RTE_FLOW_ITEM_TYPE_GENEVE: + return MLX5_GRAPH_ARC_NODE_GENEVE; + case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: + return MLX5_GRAPH_ARC_NODE_VXLAN_GPE; + default: + return -EINVAL; + } +} + +static int +mlx5_flex_arc_in_eth(const struct rte_flow_item *item, + struct rte_flow_error *error) +{ + const struct rte_flow_item_eth *spec = item->spec; + const struct rte_flow_item_eth *mask = item->mask; + struct rte_flow_item_eth eth = { .hdr.ether_type = RTE_BE16(0xFFFF) }; + + if (memcmp(mask, ð, sizeof(struct rte_flow_item_eth))) { + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, + "invalid eth item mask"); + } + return rte_be_to_cpu_16(spec->hdr.ether_type); +} + +static int +mlx5_flex_arc_in_udp(const struct rte_flow_item *item, + struct rte_flow_error *error) +{ + const struct rte_flow_item_udp *spec = item->spec; + const struct rte_flow_item_udp *mask = item->mask; + struct rte_flow_item_udp udp = { .hdr.dst_port = RTE_BE16(0xFFFF) }; + + if (memcmp(mask, &udp, sizeof(struct rte_flow_item_udp))) { + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, + "invalid eth item mask"); + } + return rte_be_to_cpu_16(spec->hdr.dst_port); +} + +static int +mlx5_flex_translate_arc_in(struct mlx5_hca_flex_attr *attr, + const struct rte_flow_item_flex_conf *conf, + struct mlx5_flex_parser_devx *devx, + struct mlx5_flex_item *item, + struct rte_flow_error *error) +{ + struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; + uint32_t i; + + RTE_SET_USED(item); + if (conf->nb_inputs > attr->max_num_arc_in) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "too many input links"); + for (i = 0; i < conf->nb_inputs; i++) { + struct mlx5_devx_graph_arc_attr *arc = node->in + i; + struct rte_flow_item_flex_link *link = conf->input_link + i; + const struct rte_flow_item *rte_item = &link->item; + int arc_type; + int ret; + + if (!rte_item->spec || !rte_item->mask || rte_item->last) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "invalid flex item IN arc format"); + arc_type = mlx5_flex_arc_type(rte_item->type, true); + if (arc_type < 0 || !(attr->node_in & RTE_BIT32(arc_type))) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported flex item IN arc type"); + arc->arc_parse_graph_node = arc_type; + arc->start_inner_tunnel = 0; + /* + * Configure arc IN condition value. The value location depends + * on protocol. Current FW version supports IP & UDP for IN + * arcs only, and locations for these protocols are defined. + * Add more protocols when available. + */ + switch (rte_item->type) { + case RTE_FLOW_ITEM_TYPE_ETH: + ret = mlx5_flex_arc_in_eth(rte_item, error); + break; + case RTE_FLOW_ITEM_TYPE_UDP: + ret = mlx5_flex_arc_in_udp(rte_item, error); + break; + default: + MLX5_ASSERT(false); + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported flex item IN arc type"); + } + if (ret < 0) + return ret; + arc->compare_condition_value = (uint16_t)ret; + } + return 0; +} + +static int +mlx5_flex_translate_arc_out(struct mlx5_hca_flex_attr *attr, + const struct rte_flow_item_flex_conf *conf, + struct mlx5_flex_parser_devx *devx, + struct mlx5_flex_item *item, + struct rte_flow_error *error) +{ + struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; + bool is_tunnel = conf->tunnel == FLEX_TUNNEL_MODE_TUNNEL; + uint32_t i; + + RTE_SET_USED(item); + if (conf->nb_outputs > attr->max_num_arc_out) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "too many output links"); + for (i = 0; i < conf->nb_outputs; i++) { + struct mlx5_devx_graph_arc_attr *arc = node->out + i; + struct rte_flow_item_flex_link *link = conf->output_link + i; + const struct rte_flow_item *rte_item = &link->item; + int arc_type; + + if (rte_item->spec || rte_item->mask || rte_item->last) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "flex node: invalid OUT arc format"); + arc_type = mlx5_flex_arc_type(rte_item->type, false); + if (arc_type < 0 || !(attr->node_out & RTE_BIT32(arc_type))) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "unsupported flex item OUT arc type"); + arc->arc_parse_graph_node = arc_type; + arc->start_inner_tunnel = !!is_tunnel; + arc->compare_condition_value = link->next; + } + return 0; +} + +/* Translate RTE flex item API configuration into flaex parser settings. */ +static int +mlx5_flex_translate_conf(struct rte_eth_dev *dev, + const struct rte_flow_item_flex_conf *conf, + struct mlx5_flex_parser_devx *devx, + struct mlx5_flex_item *item, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_hca_flex_attr *attr = &priv->config.hca_attr.flex; + int ret; + + ret = mlx5_flex_translate_length(attr, conf, devx, error); + if (ret) + return ret; + ret = mlx5_flex_translate_next(attr, conf, devx, error); + if (ret) + return ret; + ret = mlx5_flex_translate_sample(attr, conf, devx, item, error); + if (ret) + return ret; + ret = mlx5_flex_translate_arc_in(attr, conf, devx, item, error); + if (ret) + return ret; + ret = mlx5_flex_translate_arc_out(attr, conf, devx, item, error); + if (ret) + return ret; + return 0; +} + /** * Create the flex item with specified configuration over the Ethernet device. * @@ -145,6 +986,8 @@ flow_dv_item_create(struct rte_eth_dev *dev, "too many flex items created on the port"); return NULL; } + if (mlx5_flex_translate_conf(dev, conf, &devx_config, flex, error)) + goto error; ent = mlx5_list_register(priv->sh->flex_parsers_dv, &devx_config); if (!ent) { rte_flow_error_set(error, ENOMEM, @@ -153,7 +996,6 @@ flow_dv_item_create(struct rte_eth_dev *dev, goto error; } flex->devx_fp = container_of(ent, struct mlx5_flex_parser_devx, entry); - RTE_SET_USED(conf); /* Mark initialized flex item valid. */ __atomic_add_fetch(&flex->refcnt, 1, __ATOMIC_RELEASE); return (struct rte_flow_item_flex_handle *)flex; -- 2.33.1