From patchwork Tue Nov 5 09:16:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaoyu Min X-Patchwork-Id: 62448 Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 41525A0352; Tue, 5 Nov 2019 10:17:12 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8D3072C02; Tue, 5 Nov 2019 10:17:11 +0100 (CET) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id E00402BF3; Tue, 5 Nov 2019 10:17:10 +0100 (CET) From: Xiaoyu Min To: orika@mellanox.com, viacheslavo@mellanox.com, Adrien Mazarguil , Thomas Monjalon , Ferruh Yigit , Andrew Rybchenko Cc: dev@dpdk.org, stable@dpdk.org Date: Tue, 5 Nov 2019 11:16:01 +0200 Message-Id: <1580ef9551619fbe0a1f85590cebaf4b026f7f0b.1572944613.git.jackmin@mellanox.com> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH] ethdev: expand RSS flows based on last item spec X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 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" When rte_flow_expand_rss expands rte_flow item list based on the RSS types. In another word, it will add some rte_flow items if the user specified items are not complete, for example: ... pattern eth / end actions rss type tcp end ... above flow will be expaned to: ... pattern eth / end actions rss types tcp ... pattern eth / ipv4 / tcp / end actions rss types tcp ... ... pattern eth / ipv6 / tcp / end actsion rss types tcp ... However the expansion is just simply expanding items without checking last items' spec, means the expanded rules could have conflicting settings which is not reasonable and leads to some HW error, for example: ... pattern eth type is 0x86DD / end actions rss types tcp ... is expaneded to: ... pattern eth type is 0x86DD / ipv4 / tcp end ... which has conflicting values: 0x86DD vs. ipv4 and HW will refuse create flow on some NICs. This patch will fix above by checking the last item's spec and try to complete the item list. Currently only support to complete item list based on L2/L3 layer. Fixes: 4ed05fcd441b ("ethdev: add flow API to expand RSS flows") Cc: stable@dpdk.org Signed-off-by: Xiaoyu Min --- lib/librte_ethdev/rte_flow.c | 132 +++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 5 deletions(-) diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c index 2f86d1affc..ef5ce1790d 100644 --- a/lib/librte_ethdev/rte_flow.c +++ b/lib/librte_ethdev/rte_flow.c @@ -173,6 +173,67 @@ flow_err(uint16_t port_id, int ret, struct rte_flow_error *error) return ret; } +static enum rte_flow_item_type +rte_flow_expand_rss_item_complete(const struct rte_flow_item *item) +{ + enum rte_flow_item_type ret = RTE_FLOW_ITEM_TYPE_VOID; + uint16_t ether_type = 0; + uint8_t ip_next_proto = 0; + + if (item == NULL || item->spec == NULL) + return ret; + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_ETH: + ether_type = ((const struct rte_flow_item_eth *) + (item->spec))->type; + if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV4) + ret = RTE_FLOW_ITEM_TYPE_IPV4; + else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV6) + ret = RTE_FLOW_ITEM_TYPE_IPV6; + else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN) + ret = RTE_FLOW_ITEM_TYPE_VLAN; + break; + case RTE_FLOW_ITEM_TYPE_VLAN: + ether_type = ((const struct rte_flow_item_vlan *) + (item->spec))->inner_type; + if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV4) + ret = RTE_FLOW_ITEM_TYPE_IPV4; + else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV6) + ret = RTE_FLOW_ITEM_TYPE_IPV6; + else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN) + ret = RTE_FLOW_ITEM_TYPE_VLAN; + break; + case RTE_FLOW_ITEM_TYPE_IPV4: + ip_next_proto = ((const struct rte_flow_item_ipv4 *) + (item->spec))->hdr.next_proto_id; + if (ip_next_proto == IPPROTO_UDP) + ret = RTE_FLOW_ITEM_TYPE_UDP; + else if (ip_next_proto == IPPROTO_TCP) + ret = RTE_FLOW_ITEM_TYPE_TCP; + else if (ip_next_proto == IPPROTO_IP) + ret = RTE_FLOW_ITEM_TYPE_IPV4; + else if (ip_next_proto == IPPROTO_IPV6) + ret = RTE_FLOW_ITEM_TYPE_IPV6; + break; + case RTE_FLOW_ITEM_TYPE_IPV6: + ip_next_proto = ((const struct rte_flow_item_ipv6 *) + (item->spec))->hdr.proto; + if (ip_next_proto == IPPROTO_UDP) + ret = RTE_FLOW_ITEM_TYPE_UDP; + else if (ip_next_proto == IPPROTO_TCP) + ret = RTE_FLOW_ITEM_TYPE_TCP; + else if (ip_next_proto == IPPROTO_IP) + ret = RTE_FLOW_ITEM_TYPE_IPV4; + else if (ip_next_proto == IPPROTO_IPV6) + ret = RTE_FLOW_ITEM_TYPE_IPV6; + break; + default: + ret = RTE_FLOW_ITEM_TYPE_VOID; + break; + } + return ret; +} + /* Get generic flow operations structure from a port. */ const struct rte_flow_ops * rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error) @@ -932,6 +993,11 @@ rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, size_t lsize; size_t user_pattern_size = 0; void *addr = NULL; + const struct rte_flow_expand_node *next = NULL; + struct rte_flow_item missed_item; + int missed = 0; + int elt = 0; + const struct rte_flow_item *last_item = NULL; lsize = offsetof(struct rte_flow_expand_rss, entry) + elt_n * sizeof(buf->entry[0]); @@ -942,8 +1008,8 @@ rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, addr = buf->entry[0].pattern; } for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { - const struct rte_flow_expand_node *next = NULL; - + if (item->type != RTE_FLOW_ITEM_TYPE_VOID) + last_item = item; for (i = 0; node->next && node->next[i]; ++i) { next = &graph[node->next[i]]; if (next->type == item->type) @@ -964,6 +1030,41 @@ rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, /* Start expanding. */ memset(flow_items, 0, sizeof(flow_items)); user_pattern_size -= sizeof(*item); + /* + * Check if the last valid item has spec set + * and need complete pattern. + */ + missed_item.type = rte_flow_expand_rss_item_complete(last_item); + if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) { + next = NULL; + missed = 1; + for (i = 0; node->next && node->next[i]; ++i) { + next = &graph[node->next[i]]; + if (next->type == missed_item.type) { + flow_items[0].type = missed_item.type; + flow_items[1].type = RTE_FLOW_ITEM_TYPE_END; + break; + } + next = NULL; + } + } + if (next && missed) { + elt = 2; /* missed item + item end. */ + node = next; + lsize += elt * sizeof(*item) + user_pattern_size; + if ((node->rss_types & types) && lsize <= size) { + buf->entry[buf->entries].priority = 1; + buf->entry[buf->entries].pattern = addr; + buf->entries++; + rte_memcpy(addr, buf->entry[0].pattern, + user_pattern_size); + addr = (void *)(((uintptr_t)addr) + user_pattern_size); + rte_memcpy(addr, flow_items, elt * sizeof(*item)); + addr = (void *)(((uintptr_t)addr) + + elt * sizeof(*item)); + } + } + memset(flow_items, 0, sizeof(flow_items)); next_node = node->next; stack[stack_pos] = next_node; node = next_node ? &graph[*next_node] : NULL; @@ -976,21 +1077,24 @@ rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, * When the stack_pos is 0, there are 1 element in it, * plus the addition END item. */ - int elt = stack_pos + 2; - + elt = stack_pos + 2; flow_items[stack_pos + 1].type = RTE_FLOW_ITEM_TYPE_END; lsize += elt * sizeof(*item) + user_pattern_size; if (lsize <= size) { size_t n = elt * sizeof(*item); buf->entry[buf->entries].priority = - stack_pos + 1; + stack_pos + 1 + missed; buf->entry[buf->entries].pattern = addr; buf->entries++; rte_memcpy(addr, buf->entry[0].pattern, user_pattern_size); addr = (void *)(((uintptr_t)addr) + user_pattern_size); + rte_memcpy(addr, &missed_item, + missed * sizeof(*item)); + addr = (void *)(((uintptr_t)addr) + + missed * sizeof(*item)); rte_memcpy(addr, flow_items, n); addr = (void *)(((uintptr_t)addr) + n); } @@ -1015,5 +1119,23 @@ rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, } node = *next_node ? &graph[*next_node] : NULL; }; + /* no expanded flows but we have missed item, create one rule for it */ + if (buf->entries == 1 && missed != 0) { + elt = 2; + lsize += elt * sizeof(*item) + user_pattern_size; + if (lsize <= size) { + buf->entry[buf->entries].priority = 1; + buf->entry[buf->entries].pattern = addr; + buf->entries++; + flow_items[0].type = missed_item.type; + flow_items[1].type = RTE_FLOW_ITEM_TYPE_END; + rte_memcpy(addr, buf->entry[0].pattern, + user_pattern_size); + addr = (void *)(((uintptr_t)addr) + user_pattern_size); + rte_memcpy(addr, flow_items, elt * sizeof(*item)); + addr = (void *)(((uintptr_t)addr) + + elt * sizeof(*item)); + } + } return lsize; }