From: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
To: dev@dpdk.org, Adrien Mazarguil <adrien.mazarguil@6wind.com>
Subject: [dpdk-dev] [PATCH v3] ethdev: add flow API to expand RSS flows
Date: Thu, 21 Jun 2018 09:25:02 +0200 [thread overview]
Message-ID: <15e22f72e9b4c56e79809c413ce3001e4f6067d8.1529565844.git.nelio.laranjeiro@6wind.com> (raw)
In-Reply-To: <3c31112367e8d44d1568afbf52de20c6c9ff0c9c.1528187101.git.nelio.laranjeiro@6wind.com>
Introduce an helper for PMD to expand easily flows items list with RSS
action into multiple flow items lists with priority information.
For instance a user items list being "eth / end" with rss action types
"ipv4-udp ipv6-udp end" needs to be expanded into three items lists:
- eth
- eth / ipv4 / udp
- eth / ipv6 / udp
to match the user request. Some drivers are unable to reach such
request without this expansion, this API is there to help those.
Only PMD should use such API for their internal cooking, the application
will still handle a single flow.
Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
---
Changes in v3:
- Fix a segmentation fault due to an uninitialized pointer.
Changes in v2:
- Fix expansion for UDP/TCP layers where L3 may not be in the original
items list and thus is missing in the expansion.
- Fix size verification for some layers causing a segfault
---
lib/librte_ethdev/rte_flow.c | 408 ++++++++++++++++++++++++++++
lib/librte_ethdev/rte_flow_driver.h | 32 +++
2 files changed, 440 insertions(+)
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index b2afba089..9d86c20cb 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -526,3 +526,411 @@ rte_flow_copy(struct rte_flow_desc *desc, size_t len,
}
return 0;
}
+
+/* Copy the existing items list and expand with new items. */
+static int
+rte_flow_expand_rss_item(void *buf, size_t size,
+ const struct rte_flow_item *items,
+ const struct rte_flow_item *newitems)
+{
+ void *data = buf;
+ const struct rte_flow_item *item;
+ struct rte_flow_item *dst;
+ size_t data_size = 0;
+
+ dst = data;
+ /* Copy Item structure into buffer. */
+ for (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {
+ if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
+ continue;
+ if (data_size + sizeof(*item) <= size) {
+ memcpy(dst, item, sizeof(*item));
+ ++dst;
+ }
+ data_size += sizeof(*item);
+ }
+ item = newitems;
+ do {
+ if (item->type == RTE_FLOW_ITEM_TYPE_VOID) {
+ ++item;
+ continue;
+ }
+ if (data_size + sizeof(*item) <= size) {
+ memcpy(dst, item, sizeof(*item));
+ ++dst;
+ }
+ data_size += sizeof(*item);
+ ++item;
+ } while ((item - 1)->type != RTE_FLOW_ITEM_TYPE_END);
+ /**
+ * Copy Item spec, last, mask into buffer and set pointers
+ * accordingly.
+ */
+ dst = data;
+ for (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {
+ if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
+ continue;
+ if (item->spec) {
+ size_t s = flow_item_spec_copy(NULL, item, ITEM_SPEC);
+ void *addr = (data_size + s) <= size ?
+ (void *)((uintptr_t)data + data_size) :
+ NULL;
+
+ data_size += flow_item_spec_copy(addr, item, ITEM_SPEC);
+ if (addr)
+ dst->spec = addr;
+ }
+ if (item->last) {
+ size_t s = flow_item_spec_copy(NULL, item, ITEM_LAST);
+ void *addr = (data_size + s) <= size ?
+ (void *)((uintptr_t)data + data_size) :
+ NULL;
+
+ data_size += flow_item_spec_copy(addr, item, ITEM_LAST);
+ if (addr)
+ dst->last = addr;
+ }
+ if (item->mask) {
+ size_t s = flow_item_spec_copy(NULL, item, ITEM_MASK);
+ void *addr = (data_size + s) <= size ?
+ (void *)((uintptr_t)data + data_size) :
+ NULL;
+
+ data_size += flow_item_spec_copy(addr, item, ITEM_MASK);
+ if (addr)
+ dst->mask = addr;
+ }
+ if (data_size <= size)
+ ++dst;
+ }
+ return data_size;
+}
+
+/** Verify the expansion is supported by the device. */
+static int
+rte_flow_expand_rss_is_supported(const enum rte_flow_item_type **supported,
+ const enum rte_flow_item_type *expand)
+{
+ unsigned int i;
+ unsigned int sidx;
+ unsigned int eidx;
+
+ for (i = 0; supported[i]; ++i) {
+ sidx = 0;
+ eidx = 0;
+ while (1) {
+ if (expand[eidx] != supported[i][sidx]) {
+ break;
+ } else if ((expand[eidx] == RTE_FLOW_ITEM_TYPE_END) &&
+ (supported[i][sidx] ==
+ RTE_FLOW_ITEM_TYPE_END)) {
+ return 1;
+ } else if ((expand[eidx] == RTE_FLOW_ITEM_TYPE_END) ||
+ (supported[i][sidx] ==
+ RTE_FLOW_ITEM_TYPE_END)) {
+ break;
+ } else if (expand[eidx] == RTE_FLOW_ITEM_TYPE_VOID) {
+ ++eidx;
+ continue;
+ } else if (supported[i][sidx] ==
+ RTE_FLOW_ITEM_TYPE_VOID) {
+ ++sidx;
+ continue;
+ }
+ ++sidx;
+ ++eidx;
+ }
+ }
+ return 0;
+}
+
+/** Update internal buffer. */
+static inline void
+rte_flow_expand_rss_update(struct rte_flow_expand_rss *buf, void *addr,
+ uint32_t priority)
+{
+ buf->priority[buf->entries] = priority;
+ buf->patterns[buf->entries] = addr;
+ buf->entries++;
+}
+
+int
+rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size,
+ const struct rte_flow_item *pat, uint64_t types,
+ const enum rte_flow_item_type **supported)
+{
+ const struct rte_flow_item *item;
+ uint32_t priority = 0;
+ struct {
+ uint32_t eth:1; /**< Ethernet item is present. */
+ uint32_t ipv4:1; /**< IPv4 item is present. */
+ uint32_t ipv6:1; /**< IPv6 item is present. */
+ uint32_t ipv6_ex:1; /**< IPv6 EXT item is present. */
+ uint32_t udp:1; /**< UDP item is present. */
+ uint32_t tcp:1; /**< TCP item is present. */
+ uint32_t sctp:1; /**< STCP item is present. */
+ uint32_t vxlan:1; /**< VXLAN item is present. */
+ uint32_t geneve:1; /**< GENEVE item is present. */
+ uint32_t nvgre:1; /**< NVGRE item is present. */
+ } layer = { .eth = 0 };
+ const struct rte_flow_item end[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ void *addr = NULL;
+ uint32_t off; /**< Offset to write new items data starting from *buf. */
+ uint32_t max_entries;
+
+ for (max_entries = 0; supported[max_entries]; ++max_entries)
+ ;
+ off = sizeof(*buf) +
+ /* Size for the list of patterns. */
+ sizeof(*buf->patterns) +
+ RTE_ALIGN_CEIL(max_entries * sizeof(struct rte_flow_item *),
+ sizeof(void *)) +
+ /* Size for priorities. */
+ sizeof(*buf->priority) +
+ RTE_ALIGN_CEIL(max_entries * sizeof(uint32_t), sizeof(void *));
+ if (off < size) {
+ buf->priority = (void *)(buf + 1);
+ buf->patterns = (void *)&buf->priority[max_entries];
+ buf->patterns[0] = (void *)&buf->patterns[max_entries];
+ addr = buf->patterns[0];
+ buf->entries = 0;
+ }
+ /**
+ * Parse the pattern and deactivate the bit-field in RSS which cannot
+ * match anymore the pattern.
+ */
+ for (item = pat; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {
+ switch (item->type) {
+ case RTE_FLOW_ITEM_TYPE_ETH:
+ layer.eth = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ layer.ipv4 = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ layer.ipv6 = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6_EXT:
+ layer.ipv6_ex = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ layer.udp = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ layer.tcp = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_VXLAN:
+ layer.vxlan = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GENEVE:
+ layer.geneve = 1;
+ break;
+ case RTE_FLOW_ITEM_TYPE_NVGRE:
+ layer.nvgre = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ off += rte_flow_expand_rss_item(addr, (off < size) ? size - off : 0,
+ pat, end);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr, priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ if ((types & ETH_RSS_IP) &&
+ (!(layer.ipv4 || layer.ipv6 || layer.ipv6_ex))) {
+ ++priority;
+ if (types & (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |
+ ETH_RSS_NONFRAG_IPV4_OTHER)) {
+ const struct rte_flow_item new[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_IPV4 },
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ const enum rte_flow_item_type list[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_IPV4,
+ RTE_FLOW_ITEM_TYPE_END,
+ };
+ int ret;
+
+ ret = rte_flow_expand_rss_is_supported(supported, list);
+ if (ret) {
+ off += rte_flow_expand_rss_item
+ (addr, (off <= size) ? size - off : 0,
+ pat, new);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr,
+ priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ }
+ }
+ if (types & (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |
+ ETH_RSS_NONFRAG_IPV6_OTHER)) {
+ const struct rte_flow_item new[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_IPV6 },
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ const enum rte_flow_item_type list[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_IPV6,
+ RTE_FLOW_ITEM_TYPE_END,
+ };
+ int ret;
+
+ ret = rte_flow_expand_rss_is_supported(supported, list);
+ if (ret) {
+ off += rte_flow_expand_rss_item
+ (addr, (off <= size) ? size - off : 0,
+ pat, new);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr,
+ priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ }
+ }
+ if (types & ETH_RSS_IPV6_EX) {
+ const struct rte_flow_item new[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_IPV6_EXT },
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ const enum rte_flow_item_type list[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_IPV6_EXT,
+ RTE_FLOW_ITEM_TYPE_END,
+ };
+ int ret;
+
+ ret = rte_flow_expand_rss_is_supported(supported, list);
+ if (ret) {
+ off += rte_flow_expand_rss_item
+ (addr, (off <= size) ? size - off : 0,
+ pat, new);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr,
+ priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ }
+ }
+ }
+ if (types & (ETH_RSS_TCP | ETH_RSS_UDP)) {
+ ++priority;
+ if ((types & ETH_RSS_NONFRAG_IPV4_UDP) &&
+ !(layer.ipv6 || layer.ipv6_ex || layer.tcp || layer.udp)) {
+ const struct rte_flow_item new[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_IPV4 },
+ { .type = RTE_FLOW_ITEM_TYPE_UDP },
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ const enum rte_flow_item_type list[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_IPV4,
+ RTE_FLOW_ITEM_TYPE_UDP,
+ RTE_FLOW_ITEM_TYPE_END,
+ };
+ int ret;
+
+ ret = rte_flow_expand_rss_is_supported(supported, list);
+ if (ret) {
+ off += rte_flow_expand_rss_item
+ (addr, (off <= size) ? size - off : 0,
+ pat, layer.ipv4 ? &new[1] : new);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr,
+ priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ }
+ }
+ if ((types & ETH_RSS_NONFRAG_IPV4_TCP) &&
+ !(layer.ipv6 || layer.ipv6_ex || layer.tcp || layer.udp)) {
+ const struct rte_flow_item new[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_IPV4 },
+ { .type = RTE_FLOW_ITEM_TYPE_TCP },
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ const enum rte_flow_item_type list[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_IPV4,
+ RTE_FLOW_ITEM_TYPE_TCP,
+ RTE_FLOW_ITEM_TYPE_END,
+ };
+ int ret;
+
+ ret = rte_flow_expand_rss_is_supported(supported, list);
+ if (ret) {
+ off += rte_flow_expand_rss_item
+ (addr, (off <= size) ? size - off : 0,
+ pat, layer.ipv4 ? &new[1] : new);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr,
+ priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ }
+ }
+ if ((types & ETH_RSS_NONFRAG_IPV6_UDP) &&
+ !(layer.ipv4 || layer.tcp || layer.udp)) {
+ const struct rte_flow_item new[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_IPV6 },
+ { .type = RTE_FLOW_ITEM_TYPE_UDP },
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ const enum rte_flow_item_type list[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_IPV6,
+ RTE_FLOW_ITEM_TYPE_UDP,
+ RTE_FLOW_ITEM_TYPE_END,
+ };
+ int ret;
+
+ ret = rte_flow_expand_rss_is_supported(supported, list);
+ if (ret) {
+ off += rte_flow_expand_rss_item
+ (addr, (off <= size) ? size - off : 0,
+ pat, layer.ipv6 ? &new[1] : new);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr,
+ priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ }
+ }
+ if ((types & (ETH_RSS_NONFRAG_IPV6_TCP |
+ ETH_RSS_IPV6_TCP_EX)) &&
+ !(layer.ipv4 || layer.tcp || layer.udp)) {
+ const struct rte_flow_item new[] = {
+ { .type = RTE_FLOW_ITEM_TYPE_IPV6 },
+ { .type = RTE_FLOW_ITEM_TYPE_TCP },
+ { .type = RTE_FLOW_ITEM_TYPE_END },
+ };
+ const enum rte_flow_item_type list[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ (layer.ipv6_ex ?
+ RTE_FLOW_ITEM_TYPE_IPV6_EXT :
+ RTE_FLOW_ITEM_TYPE_IPV6),
+ RTE_FLOW_ITEM_TYPE_UDP,
+ RTE_FLOW_ITEM_TYPE_END,
+ };
+ int ret;
+
+ ret = rte_flow_expand_rss_is_supported(supported, list);
+ if (ret) {
+ off += rte_flow_expand_rss_item
+ (addr, (off <= size) ? size - off : 0,
+ pat, layer.ipv6 ? &new[1] : new);
+ if (off <= size) {
+ rte_flow_expand_rss_update(buf, addr,
+ priority);
+ addr = (void *)((uintptr_t)buf + off);
+ }
+ }
+ }
+ }
+ return off;
+}
diff --git a/lib/librte_ethdev/rte_flow_driver.h b/lib/librte_ethdev/rte_flow_driver.h
index 1c90c600d..9058a8715 100644
--- a/lib/librte_ethdev/rte_flow_driver.h
+++ b/lib/librte_ethdev/rte_flow_driver.h
@@ -114,6 +114,38 @@ struct rte_flow_ops {
const struct rte_flow_ops *
rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error);
+/**
+ * Expansion structure for RSS flows.
+ */
+struct rte_flow_expand_rss {
+ uint32_t entries; /**< Number of entries in the following arrays. */
+ struct rte_flow_item **patterns; /**< Expanded pattern array. */
+ uint32_t *priority; /**< Priority offset for each expansion. */
+};
+
+/**
+ * Expand RSS flows into several possible flows according to the RSS hash
+ * fields requested and the driver capabilities.
+ *
+ * @param[in,out] buf
+ * Buffer to store the result expansion.
+ * @param[in] size
+ * Size in octets of the buffer.
+ * @param[in] pat
+ * User flow pattern.
+ * @param[in] types
+ * RSS types expected (see ETH_RSS_*).
+ * @param[in] supported.
+ * List of support expansion pattern from the device.
+ *
+ * @return
+ * The size in octets used to expand.
+ */
+int
+rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size,
+ const struct rte_flow_item *pat, uint64_t types,
+ const enum rte_flow_item_type **supported);
+
#ifdef __cplusplus
}
#endif
--
2.18.0.rc2
next prev parent reply other threads:[~2018-06-21 7:24 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-28 9:54 [dpdk-dev] [DPDK 18.08] " Nelio Laranjeiro
2018-05-28 13:33 ` Wiles, Keith
2018-06-05 8:26 ` [dpdk-dev] [PATCH v2] " Nelio Laranjeiro
2018-06-21 7:25 ` Nelio Laranjeiro [this message]
2018-06-27 14:26 ` [dpdk-dev] [PATCH v3] " Thomas Monjalon
2018-06-27 14:55 ` [dpdk-dev] [PATCH v4] " Nelio Laranjeiro
2018-06-28 12:33 ` Adrien Mazarguil
2018-06-28 16:01 ` [dpdk-dev] [PATCH v5] " Nelio Laranjeiro
2018-06-28 16:09 ` Adrien Mazarguil
2018-06-29 16:23 ` Ferruh Yigit
2018-06-29 16:26 ` Ferruh Yigit
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=15e22f72e9b4c56e79809c413ce3001e4f6067d8.1529565844.git.nelio.laranjeiro@6wind.com \
--to=nelio.laranjeiro@6wind.com \
--cc=adrien.mazarguil@6wind.com \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).