DPDK patches and discussions
 help / color / mirror / Atom feed
From: Adrien Mazarguil <adrien.mazarguil@6wind.com>
To: Ferruh Yigit <ferruh.yigit@intel.com>
Cc: dev@dpdk.org, Thomas Monjalon <thomas@monjalon.net>,
	Andrew Rybchenko <arybchenko@solarflare.com>,
	Gaetan Rivet <gaetan.rivet@6wind.com>
Subject: [dpdk-dev] [PATCH v2 1/7] ethdev: add flow API object converter
Date: Fri, 3 Aug 2018 15:36:32 +0200	[thread overview]
Message-ID: <20180803132032.29038-2-adrien.mazarguil@6wind.com> (raw)
In-Reply-To: <20180803132032.29038-1-adrien.mazarguil@6wind.com>

rte_flow_copy() is bound to duplicate flow rule descriptions (attributes,
pattern and list of actions, all at once), however applications sometimes
need more flexibility, for instance the ability to duplicate only one of
the underlying objects (a single pattern item or action) or retrieve other
properties such as their names.

Instead of adding dedicated functions to handle each possible use case,
this patch introduces rte_flow_conv(), which supports any number of object
conversion operations in an extensible manner.

This patch re-implements rte_flow_copy() as a wrapper to rte_flow_conv().

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Cc: Thomas Monjalon <thomas@monjalon.net>
Cc: Ferruh Yigit <ferruh.yigit@intel.com>
Cc: Andrew Rybchenko <arybchenko@solarflare.com>
Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
--
v2 changes:

- Modified patch to keep rte_flow_copy() around instead of removing it
  entirely. Reworded commit log accordingly.

- Moved failsafe PMD changes to a subsequent patch.

- Re-implemented rte_flow_copy() as a wrapper to rte_flow_conv() to reduce
  code duplication.

- Tweaked semantics of rte_flow_conv() to return the required number of
  bytes regardless of the size parameter; a buffer not large enough is not
  considered to be an error anymore. This change removes the need for a
  "store" pass in underlying helper functions.

- Renamed and properly documented internal helper functions.
---
 doc/guides/prog_guide/rte_flow.rst       |  19 +
 lib/librte_ethdev/rte_ethdev_version.map |   1 +
 lib/librte_ethdev/rte_flow.c             | 553 ++++++++++++++++++--------
 lib/librte_ethdev/rte_flow.h             | 169 +++++++-
 4 files changed, 581 insertions(+), 161 deletions(-)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index b305a72a5..964cf9ceb 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2419,6 +2419,25 @@ This function initializes ``error`` (if non-NULL) with the provided
 parameters and sets ``rte_errno`` to ``code``. A negative error ``code`` is
 then returned.
 
+Object conversion
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: c
+
+   int
+   rte_flow_conv(enum rte_flow_conv_op op,
+                 void *dst,
+                 size_t size,
+                 const void *src,
+                 struct rte_flow_error *error);
+
+Convert ``src`` to ``dst`` according to operation ``op``. Possible
+operations include:
+
+- Attributes, pattern item or action duplication.
+- Duplication of an entire pattern or list of actions.
+- Duplication of a complete flow rule description.
+
 Caveats
 -------
 
diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map
index 38f117f01..2345f3002 100644
--- a/lib/librte_ethdev/rte_ethdev_version.map
+++ b/lib/librte_ethdev/rte_ethdev_version.map
@@ -217,6 +217,7 @@ DPDK_18.08 {
 	global:
 
 	rte_eth_dev_logtype;
+	rte_flow_conv;
 
 } DPDK_18.05;
 
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index cff4b5209..930fe09c8 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -288,26 +288,41 @@ rte_flow_error_set(struct rte_flow_error *error,
 }
 
 /** Pattern item specification types. */
-enum item_spec_type {
-	ITEM_SPEC,
-	ITEM_LAST,
-	ITEM_MASK,
+enum rte_flow_conv_item_spec_type {
+	RTE_FLOW_CONV_ITEM_SPEC,
+	RTE_FLOW_CONV_ITEM_LAST,
+	RTE_FLOW_CONV_ITEM_MASK,
 };
 
-/** Compute storage space needed by item specification and copy it. */
+/**
+ * Copy pattern item specification.
+ *
+ * @param[out] buf
+ *   Output buffer. Can be NULL if @p size is zero.
+ * @param size
+ *   Size of @p buf in bytes.
+ * @param[in] item
+ *   Pattern item to copy specification from.
+ * @param type
+ *   Specification selector for either @p spec, @p last or @p mask.
+ *
+ * @return
+ *   Number of bytes needed to store pattern item specification regardless
+ *   of @p size. @p buf contents are truncated to @p size if not large
+ *   enough.
+ */
 static size_t
-flow_item_spec_copy(void *buf, const struct rte_flow_item *item,
-		    enum item_spec_type type)
+rte_flow_conv_item_spec(void *buf, const size_t size,
+			const struct rte_flow_item *item,
+			enum rte_flow_conv_item_spec_type type)
 {
-	size_t size = 0;
+	size_t off;
 	const void *data =
-		type == ITEM_SPEC ? item->spec :
-		type == ITEM_LAST ? item->last :
-		type == ITEM_MASK ? item->mask :
+		type == RTE_FLOW_CONV_ITEM_SPEC ? item->spec :
+		type == RTE_FLOW_CONV_ITEM_LAST ? item->last :
+		type == RTE_FLOW_CONV_ITEM_MASK ? item->mask :
 		NULL;
 
-	if (!item->spec || !data)
-		goto empty;
 	switch (item->type) {
 		union {
 			const struct rte_flow_item_raw *raw;
@@ -324,7 +339,7 @@ flow_item_spec_copy(void *buf, const struct rte_flow_item *item,
 		union {
 			struct rte_flow_item_raw *raw;
 		} dst;
-		size_t off;
+		size_t tmp;
 
 	case RTE_FLOW_ITEM_TYPE_RAW:
 		spec.raw = item->spec;
@@ -332,41 +347,62 @@ flow_item_spec_copy(void *buf, const struct rte_flow_item *item,
 		mask.raw = item->mask ? item->mask : &rte_flow_item_raw_mask;
 		src.raw = data;
 		dst.raw = buf;
-		off = RTE_ALIGN_CEIL(sizeof(struct rte_flow_item_raw),
-				     sizeof(*src.raw->pattern));
-		if (type == ITEM_SPEC ||
-		    (type == ITEM_MASK &&
+		rte_memcpy(dst.raw,
+			   &(struct rte_flow_item_raw){
+				.relative = src.raw->relative,
+				.search = src.raw->search,
+				.reserved = src.raw->reserved,
+				.offset = src.raw->offset,
+				.limit = src.raw->limit,
+				.length = src.raw->length,
+			   },
+			   (size > sizeof(*dst.raw) ? sizeof(*dst.raw) : size));
+		off = sizeof(*dst.raw);
+		if (type == RTE_FLOW_CONV_ITEM_SPEC ||
+		    (type == RTE_FLOW_CONV_ITEM_MASK &&
 		     ((spec.raw->length & mask.raw->length) >=
 		      (last.raw->length & mask.raw->length))))
-			size = spec.raw->length & mask.raw->length;
+			tmp = spec.raw->length & mask.raw->length;
 		else
-			size = last.raw->length & mask.raw->length;
-		size = off + size * sizeof(*src.raw->pattern);
-		if (dst.raw) {
-			memcpy(dst.raw, src.raw, sizeof(*src.raw));
-			dst.raw->pattern = memcpy((uint8_t *)dst.raw + off,
-						  src.raw->pattern,
-						  size - off);
+			tmp = last.raw->length & mask.raw->length;
+		if (tmp) {
+			off = RTE_ALIGN_CEIL(off, sizeof(*dst.raw->pattern));
+			if (size >= off + tmp)
+				dst.raw->pattern = rte_memcpy
+					((void *)((uintptr_t)dst.raw + off),
+					 src.raw->pattern, tmp);
+			off += tmp;
 		}
 		break;
 	default:
-		size = rte_flow_desc_item[item->type].size;
-		if (buf)
-			memcpy(buf, data, size);
+		off = rte_flow_desc_item[item->type].size;
+		rte_memcpy(buf, data, (size > off ? off : size));
 		break;
 	}
-empty:
-	return RTE_ALIGN_CEIL(size, sizeof(double));
+	return off;
 }
 
-/** Compute storage space needed by action configuration and copy it. */
+/**
+ * Copy action configuration.
+ *
+ * @param[out] buf
+ *   Output buffer. Can be NULL if @p size is zero.
+ * @param size
+ *   Size of @p buf in bytes.
+ * @param[in] action
+ *   Action to copy configuration from.
+ *
+ * @return
+ *   Number of bytes needed to store pattern item specification regardless
+ *   of @p size. @p buf contents are truncated to @p size if not large
+ *   enough.
+ */
 static size_t
-flow_action_conf_copy(void *buf, const struct rte_flow_action *action)
+rte_flow_conv_action_conf(void *buf, const size_t size,
+			  const struct rte_flow_action *action)
 {
-	size_t size = 0;
+	size_t off;
 
-	if (!action->conf)
-		goto empty;
 	switch (action->type) {
 		union {
 			const struct rte_flow_action_rss *rss;
@@ -374,49 +410,308 @@ flow_action_conf_copy(void *buf, const struct rte_flow_action *action)
 		union {
 			struct rte_flow_action_rss *rss;
 		} dst;
-		size_t off;
+		size_t tmp;
 
 	case RTE_FLOW_ACTION_TYPE_RSS:
 		src.rss = action->conf;
 		dst.rss = buf;
-		off = 0;
-		if (dst.rss)
-			*dst.rss = (struct rte_flow_action_rss){
+		rte_memcpy(dst.rss,
+			   &(struct rte_flow_action_rss){
 				.func = src.rss->func,
 				.level = src.rss->level,
 				.types = src.rss->types,
 				.key_len = src.rss->key_len,
 				.queue_num = src.rss->queue_num,
-			};
-		off += sizeof(*src.rss);
+			   },
+			   (size > sizeof(*dst.rss) ? sizeof(*dst.rss) : size));
+		off = sizeof(*dst.rss);
 		if (src.rss->key_len) {
-			off = RTE_ALIGN_CEIL(off, sizeof(double));
-			size = sizeof(*src.rss->key) * src.rss->key_len;
-			if (dst.rss)
-				dst.rss->key = memcpy
+			off = RTE_ALIGN_CEIL(off, sizeof(*dst.rss->key));
+			tmp = sizeof(*src.rss->key) * src.rss->key_len;
+			if (size >= off + tmp)
+				dst.rss->key = rte_memcpy
 					((void *)((uintptr_t)dst.rss + off),
-					 src.rss->key, size);
-			off += size;
+					 src.rss->key, tmp);
+			off += tmp;
 		}
 		if (src.rss->queue_num) {
-			off = RTE_ALIGN_CEIL(off, sizeof(double));
-			size = sizeof(*src.rss->queue) * src.rss->queue_num;
-			if (dst.rss)
-				dst.rss->queue = memcpy
+			off = RTE_ALIGN_CEIL(off, sizeof(*dst.rss->queue));
+			tmp = sizeof(*src.rss->queue) * src.rss->queue_num;
+			if (size >= off + tmp)
+				dst.rss->queue = rte_memcpy
 					((void *)((uintptr_t)dst.rss + off),
-					 src.rss->queue, size);
-			off += size;
+					 src.rss->queue, tmp);
+			off += tmp;
 		}
-		size = off;
 		break;
 	default:
-		size = rte_flow_desc_action[action->type].size;
-		if (buf)
-			memcpy(buf, action->conf, size);
+		off = rte_flow_desc_action[action->type].size;
+		rte_memcpy(buf, action->conf, (size > off ? off : size));
 		break;
 	}
-empty:
-	return RTE_ALIGN_CEIL(size, sizeof(double));
+	return off;
+}
+
+/**
+ * Copy a list of pattern items.
+ *
+ * @param[out] dst
+ *   Destination buffer. Can be NULL if @p size is zero.
+ * @param size
+ *   Size of @p dst in bytes.
+ * @param[in] src
+ *   Source pattern items.
+ * @param num
+ *   Maximum number of pattern items to process from @p src or 0 to process
+ *   the entire list. In both cases, processing stops after
+ *   RTE_FLOW_ITEM_TYPE_END is encountered.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   A positive value representing the number of bytes needed to store
+ *   pattern items regardless of @p size on success (@p buf contents are
+ *   truncated to @p size if not large enough), a negative errno value
+ *   otherwise and rte_errno is set.
+ */
+static int
+rte_flow_conv_pattern(struct rte_flow_item *dst,
+		      const size_t size,
+		      const struct rte_flow_item *src,
+		      unsigned int num,
+		      struct rte_flow_error *error)
+{
+	uintptr_t data = (uintptr_t)dst;
+	size_t off;
+	size_t ret;
+	unsigned int i;
+
+	for (i = 0, off = 0; !num || i != num; ++i, ++src, ++dst) {
+		if ((size_t)src->type >= RTE_DIM(rte_flow_desc_item) ||
+		    !rte_flow_desc_item[src->type].name)
+			return rte_flow_error_set
+				(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, src,
+				 "cannot convert unknown item type");
+		if (size >= off + sizeof(*dst))
+			*dst = (struct rte_flow_item){
+				.type = src->type,
+			};
+		off += sizeof(*dst);
+		if (!src->type)
+			num = i + 1;
+	}
+	num = i;
+	src -= num;
+	dst -= num;
+	do {
+		if (src->spec) {
+			off = RTE_ALIGN_CEIL(off, sizeof(double));
+			ret = rte_flow_conv_item_spec
+				((void *)(data + off),
+				 size > off ? size - off : 0, src,
+				 RTE_FLOW_CONV_ITEM_SPEC);
+			if (size && size >= off + ret)
+				dst->spec = (void *)(data + off);
+			off += ret;
+
+		}
+		if (src->last) {
+			off = RTE_ALIGN_CEIL(off, sizeof(double));
+			ret = rte_flow_conv_item_spec
+				((void *)(data + off),
+				 size > off ? size - off : 0, src,
+				 RTE_FLOW_CONV_ITEM_LAST);
+			if (size && size >= off + ret)
+				dst->last = (void *)(data + off);
+			off += ret;
+		}
+		if (src->mask) {
+			off = RTE_ALIGN_CEIL(off, sizeof(double));
+			ret = rte_flow_conv_item_spec
+				((void *)(data + off),
+				 size > off ? size - off : 0, src,
+				 RTE_FLOW_CONV_ITEM_MASK);
+			if (size && size >= off + ret)
+				dst->mask = (void *)(data + off);
+			off += ret;
+		}
+		++src;
+		++dst;
+	} while (--num);
+	return off;
+}
+
+/**
+ * Copy a list of actions.
+ *
+ * @param[out] dst
+ *   Destination buffer. Can be NULL if @p size is zero.
+ * @param size
+ *   Size of @p dst in bytes.
+ * @param[in] src
+ *   Source actions.
+ * @param num
+ *   Maximum number of actions to process from @p src or 0 to process the
+ *   entire list. In both cases, processing stops after
+ *   RTE_FLOW_ACTION_TYPE_END is encountered.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   A positive value representing the number of bytes needed to store
+ *   actions regardless of @p size on success (@p buf contents are truncated
+ *   to @p size if not large enough), a negative errno value otherwise and
+ *   rte_errno is set.
+ */
+static int
+rte_flow_conv_actions(struct rte_flow_action *dst,
+		      const size_t size,
+		      const struct rte_flow_action *src,
+		      unsigned int num,
+		      struct rte_flow_error *error)
+{
+	uintptr_t data = (uintptr_t)dst;
+	size_t off;
+	size_t ret;
+	unsigned int i;
+
+	for (i = 0, off = 0; !num || i != num; ++i, ++src, ++dst) {
+		if ((size_t)src->type >= RTE_DIM(rte_flow_desc_action) ||
+		    !rte_flow_desc_action[src->type].name)
+			return rte_flow_error_set
+				(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
+				 src, "cannot convert unknown action type");
+		if (size >= off + sizeof(*dst))
+			*dst = (struct rte_flow_action){
+				.type = src->type,
+			};
+		off += sizeof(*dst);
+		if (!src->type)
+			num = i + 1;
+	}
+	num = i;
+	src -= num;
+	dst -= num;
+	do {
+		if (src->conf) {
+			off = RTE_ALIGN_CEIL(off, sizeof(double));
+			ret = rte_flow_conv_action_conf
+				((void *)(data + off),
+				 size > off ? size - off : 0, src);
+			if (size && size >= off + ret)
+				dst->conf = (void *)(data + off);
+			off += ret;
+		}
+		++src;
+		++dst;
+	} while (--num);
+	return off;
+}
+
+/**
+ * Copy flow rule components.
+ *
+ * This comprises the flow rule descriptor itself, attributes, pattern and
+ * actions list. NULL components in @p src are skipped.
+ *
+ * @param[out] dst
+ *   Destination buffer. Can be NULL if @p size is zero.
+ * @param size
+ *   Size of @p dst in bytes.
+ * @param[in] src
+ *   Source flow rule descriptor.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   A positive value representing the number of bytes needed to store all
+ *   components including the descriptor regardless of @p size on success
+ *   (@p buf contents are truncated to @p size if not large enough), a
+ *   negative errno value otherwise and rte_errno is set.
+ */
+static int
+rte_flow_conv_rule(struct rte_flow_conv_rule *dst,
+		   const size_t size,
+		   const struct rte_flow_conv_rule *src,
+		   struct rte_flow_error *error)
+{
+	size_t off;
+	int ret;
+
+	rte_memcpy(dst,
+		   &(struct rte_flow_conv_rule){
+			.attr = NULL,
+			.pattern = NULL,
+			.actions = NULL,
+		   },
+		   (size > sizeof(*dst) ? sizeof(*dst) : size));
+	off = sizeof(*dst);
+	if (src->attr_ro) {
+		off = RTE_ALIGN_CEIL(off, sizeof(double));
+		if (size && size >= off + sizeof(*dst->attr))
+			dst->attr = rte_memcpy
+				((void *)((uintptr_t)dst + off),
+				 src->attr_ro, sizeof(*dst->attr));
+		off += sizeof(*dst->attr);
+	}
+	if (src->pattern_ro) {
+		off = RTE_ALIGN_CEIL(off, sizeof(double));
+		ret = rte_flow_conv_pattern((void *)((uintptr_t)dst + off),
+					    size > off ? size - off : 0,
+					    src->pattern_ro, 0, error);
+		if (ret < 0)
+			return ret;
+		if (size && size >= off + (size_t)ret)
+			dst->pattern = (void *)((uintptr_t)dst + off);
+		off += ret;
+	}
+	if (src->actions_ro) {
+		off = RTE_ALIGN_CEIL(off, sizeof(double));
+		ret = rte_flow_conv_actions((void *)((uintptr_t)dst + off),
+					    size > off ? size - off : 0,
+					    src->actions_ro, 0, error);
+		if (ret < 0)
+			return ret;
+		if (size >= off + (size_t)ret)
+			dst->actions = (void *)((uintptr_t)dst + off);
+		off += ret;
+	}
+	return off;
+}
+
+/** Helper function to convert flow API objects. */
+int
+rte_flow_conv(enum rte_flow_conv_op op,
+	      void *dst,
+	      size_t size,
+	      const void *src,
+	      struct rte_flow_error *error)
+{
+	switch (op) {
+		const struct rte_flow_attr *attr;
+
+	case RTE_FLOW_CONV_OP_NONE:
+		return 0;
+	case RTE_FLOW_CONV_OP_ATTR:
+		attr = src;
+		if (size > sizeof(*attr))
+			size = sizeof(*attr);
+		rte_memcpy(dst, attr, size);
+		return sizeof(*attr);
+	case RTE_FLOW_CONV_OP_ITEM:
+		return rte_flow_conv_pattern(dst, size, src, 1, error);
+	case RTE_FLOW_CONV_OP_ACTION:
+		return rte_flow_conv_actions(dst, size, src, 1, error);
+	case RTE_FLOW_CONV_OP_PATTERN:
+		return rte_flow_conv_pattern(dst, size, src, 0, error);
+	case RTE_FLOW_CONV_OP_ACTIONS:
+		return rte_flow_conv_actions(dst, size, src, 0, error);
+	case RTE_FLOW_CONV_OP_RULE:
+		return rte_flow_conv_rule(dst, size, src, error);
+	}
+	return rte_flow_error_set
+		(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+		 "unknown object conversion operation");
 }
 
 /** Store a full rte_flow description. */
@@ -426,105 +721,49 @@ rte_flow_copy(struct rte_flow_desc *desc, size_t len,
 	      const struct rte_flow_item *items,
 	      const struct rte_flow_action *actions)
 {
-	struct rte_flow_desc *fd = NULL;
-	size_t tmp;
-	size_t off1 = 0;
-	size_t off2 = 0;
-	size_t size = 0;
-
-store:
-	if (items) {
-		const struct rte_flow_item *item;
-
-		item = items;
-		if (fd)
-			fd->items = (void *)&fd->data[off1];
-		do {
-			struct rte_flow_item *dst = NULL;
-
-			if ((size_t)item->type >=
-				RTE_DIM(rte_flow_desc_item) ||
-			    !rte_flow_desc_item[item->type].name) {
-				rte_errno = ENOTSUP;
-				return 0;
-			}
-			if (fd)
-				dst = memcpy(fd->data + off1, item,
-					     sizeof(*item));
-			off1 += sizeof(*item);
-			if (item->spec) {
-				if (fd)
-					dst->spec = fd->data + off2;
-				off2 += flow_item_spec_copy
-					(fd ? fd->data + off2 : NULL, item,
-					 ITEM_SPEC);
-			}
-			if (item->last) {
-				if (fd)
-					dst->last = fd->data + off2;
-				off2 += flow_item_spec_copy
-					(fd ? fd->data + off2 : NULL, item,
-					 ITEM_LAST);
-			}
-			if (item->mask) {
-				if (fd)
-					dst->mask = fd->data + off2;
-				off2 += flow_item_spec_copy
-					(fd ? fd->data + off2 : NULL, item,
-					 ITEM_MASK);
-			}
-			off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-		} while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
-		off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-	}
-	if (actions) {
-		const struct rte_flow_action *action;
-
-		action = actions;
-		if (fd)
-			fd->actions = (void *)&fd->data[off1];
-		do {
-			struct rte_flow_action *dst = NULL;
-
-			if ((size_t)action->type >=
-				RTE_DIM(rte_flow_desc_action) ||
-			    !rte_flow_desc_action[action->type].name) {
-				rte_errno = ENOTSUP;
-				return 0;
-			}
-			if (fd)
-				dst = memcpy(fd->data + off1, action,
-					     sizeof(*action));
-			off1 += sizeof(*action);
-			if (action->conf) {
-				if (fd)
-					dst->conf = fd->data + off2;
-				off2 += flow_action_conf_copy
-					(fd ? fd->data + off2 : NULL, action);
-			}
-			off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-		} while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
+	/*
+	 * Overlap struct rte_flow_conv with struct rte_flow_desc in order
+	 * to convert the former to the latter without wasting space.
+	 */
+	struct rte_flow_conv_rule *dst =
+		len ?
+		(void *)((uintptr_t)desc +
+			 (offsetof(struct rte_flow_desc, actions) -
+			  offsetof(struct rte_flow_conv_rule, actions))) :
+		NULL;
+	size_t dst_size =
+		len > sizeof(*desc) - sizeof(*dst) ?
+		len - (sizeof(*desc) - sizeof(*dst)) :
+		0;
+	struct rte_flow_conv_rule src = {
+		.attr_ro = NULL,
+		.pattern_ro = items,
+		.actions_ro = actions,
+	};
+	int ret;
+
+	RTE_BUILD_BUG_ON(sizeof(struct rte_flow_desc) <
+			 sizeof(struct rte_flow_conv_rule));
+	if (dst_size &&
+	    (&dst->pattern != &desc->items ||
+	     &dst->actions != &desc->actions ||
+	     (uintptr_t)(dst + 1) != (uintptr_t)(desc + 1))) {
+		rte_errno = EINVAL;
+		return 0;
 	}
-	if (fd != NULL)
-		return size;
-	off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-	tmp = RTE_ALIGN_CEIL(offsetof(struct rte_flow_desc, data),
-			     sizeof(double));
-	size = tmp + off1 + off2;
-	if (size > len)
-		return size;
-	fd = desc;
-	if (fd != NULL) {
-		*fd = (const struct rte_flow_desc) {
-			.size = size,
+	ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, dst, dst_size, &src, NULL);
+	if (ret < 0)
+		return 0;
+	ret += sizeof(*desc) - sizeof(*dst);
+	rte_memcpy(desc,
+		   &(struct rte_flow_desc){
+			.size = ret,
 			.attr = *attr,
-		};
-		tmp -= offsetof(struct rte_flow_desc, data);
-		off2 = tmp + off1;
-		off1 = tmp;
-		goto store;
-	}
-	return 0;
+			.items = dst_size ? dst->pattern : NULL,
+			.actions = dst_size ? dst->actions : NULL,
+		   },
+		   (len > sizeof(*desc) ? sizeof(*desc) : len));
+	return ret;
 }
 
 /**
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index f8ba71cdb..71dc30e4c 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -18,6 +18,7 @@
 #include <stdint.h>
 
 #include <rte_arp.h>
+#include <rte_common.h>
 #include <rte_ether.h>
 #include <rte_eth_ctrl.h>
 #include <rte_icmp.h>
@@ -1932,6 +1933,119 @@ struct rte_flow_error {
 };
 
 /**
+ * Complete flow rule description.
+ *
+ * This object type is used when converting a flow rule description.
+ *
+ * @see RTE_FLOW_CONV_OP_RULE
+ * @see rte_flow_conv()
+ */
+RTE_STD_C11
+struct rte_flow_conv_rule {
+	union {
+		const struct rte_flow_attr *attr_ro; /**< RO attributes. */
+		struct rte_flow_attr *attr; /**< Attributes. */
+	};
+	union {
+		const struct rte_flow_item *pattern_ro; /**< RO pattern. */
+		struct rte_flow_item *pattern; /**< Pattern items. */
+	};
+	union {
+		const struct rte_flow_action *actions_ro; /**< RO actions. */
+		struct rte_flow_action *actions; /**< List of actions. */
+	};
+};
+
+/**
+ * Conversion operations for flow API objects.
+ *
+ * @see rte_flow_conv()
+ */
+enum rte_flow_conv_op {
+	/**
+	 * No operation to perform.
+	 *
+	 * rte_flow_conv() simply returns 0.
+	 */
+	RTE_FLOW_CONV_OP_NONE,
+
+	/**
+	 * Convert attributes structure.
+	 *
+	 * This is a basic copy of an attributes structure.
+	 *
+	 * - @p src type:
+	 *   @code const struct rte_flow_attr * @endcode
+	 * - @p dst type:
+	 *   @code struct rte_flow_attr * @endcode
+	 */
+	RTE_FLOW_CONV_OP_ATTR,
+
+	/**
+	 * Convert a single item.
+	 *
+	 * Duplicates @p spec, @p last and @p mask but not outside objects.
+	 *
+	 * - @p src type:
+	 *   @code const struct rte_flow_item * @endcode
+	 * - @p dst type:
+	 *   @code struct rte_flow_item * @endcode
+	 */
+	RTE_FLOW_CONV_OP_ITEM,
+
+	/**
+	 * Convert a single action.
+	 *
+	 * Duplicates @p conf but not outside objects.
+	 *
+	 * - @p src type:
+	 *   @code const struct rte_flow_action * @endcode
+	 * - @p dst type:
+	 *   @code struct rte_flow_action * @endcode
+	 */
+	RTE_FLOW_CONV_OP_ACTION,
+
+	/**
+	 * Convert an entire pattern.
+	 *
+	 * Duplicates all pattern items at once with the same constraints as
+	 * RTE_FLOW_CONV_OP_ITEM.
+	 *
+	 * - @p src type:
+	 *   @code const struct rte_flow_item * @endcode
+	 * - @p dst type:
+	 *   @code struct rte_flow_item * @endcode
+	 */
+	RTE_FLOW_CONV_OP_PATTERN,
+
+	/**
+	 * Convert a list of actions.
+	 *
+	 * Duplicates the entire list of actions at once with the same
+	 * constraints as RTE_FLOW_CONV_OP_ACTION.
+	 *
+	 * - @p src type:
+	 *   @code const struct rte_flow_action * @endcode
+	 * - @p dst type:
+	 *   @code struct rte_flow_action * @endcode
+	 */
+	RTE_FLOW_CONV_OP_ACTIONS,
+
+	/**
+	 * Convert a complete flow rule description.
+	 *
+	 * Comprises attributes, pattern and actions together at once with
+	 * the usual constraints.
+	 *
+	 * - @p src type:
+	 *   @code const struct rte_flow_conv_rule * @endcode
+	 * - @p dst type:
+	 *   @code struct rte_flow_conv_rule * @endcode
+	 */
+	RTE_FLOW_CONV_OP_RULE,
+};
+
+/**
  * Check whether a flow rule can be created on a given port.
  *
  * The flow rule is validated for correctness and whether it could be accepted
@@ -2162,10 +2276,7 @@ rte_flow_error_set(struct rte_flow_error *error,
 		   const char *message);
 
 /**
- * Generic flow representation.
- *
- * This form is sufficient to describe an rte_flow independently from any
- * PMD implementation and allows for replayability and identification.
+ * @see rte_flow_copy()
  */
 struct rte_flow_desc {
 	size_t size; /**< Allocated space including data[]. */
@@ -2178,6 +2289,9 @@ struct rte_flow_desc {
 /**
  * Copy an rte_flow rule description.
  *
+ * This interface is kept for compatibility with older applications but is
+ * implemented as a wrapper to rte_flow_conv().
+ *
  * @param[in] fd
  *   Flow rule description.
  * @param[in] len
@@ -2201,6 +2315,53 @@ rte_flow_copy(struct rte_flow_desc *fd, size_t len,
 	      const struct rte_flow_item *items,
 	      const struct rte_flow_action *actions);
 
+/**
+ * Flow object conversion helper.
+ *
+ * This function performs conversion of various flow API objects to a
+ * pre-allocated destination buffer. See enum rte_flow_conv_op for possible
+ * operations and details about each of them.
+ *
+ * Since destination buffer must be large enough, it works in a manner
+ * reminiscent of snprintf():
+ *
+ * - If @p size is 0, @p dst may be a NULL pointer, otherwise @p dst must be
+ *   non-NULL.
+ * - If positive, the returned value represents the number of bytes needed
+ *   to store the conversion of @p src to @p dst according to @p op
+ *   regardless of the @p size parameter.
+ * - Since no more than @p size bytes can be written to @p dst, output is
+ *   truncated and may be inconsistent when the returned value is larger
+ *   than that.
+ * - In case of conversion error, a negative error code is returned and
+ *   @p dst contents are unspecified.
+ *
+ * @param op
+ *   Operation to perform, related to the object type of @p dst.
+ * @param[out] dst
+ *   Destination buffer address. Must be suitably aligned by the caller.
+ * @param size
+ *   Destination buffer size in bytes.
+ * @param[in] src
+ *   Source object to copy. Depending on @p op, its type may differ from
+ *   that of @p dst.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   The number of bytes required to convert @p src to @p dst on success, a
+ *   negative errno value otherwise and rte_errno is set.
+ *
+ * @see rte_flow_conv_op
+ */
+int
+rte_flow_conv(enum rte_flow_conv_op op,
+	      void *dst,
+	      size_t size,
+	      const void *src,
+	      struct rte_flow_error *error);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

  reply	other threads:[~2018-08-03 13:36 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-05  9:49 [dpdk-dev] [PATCH v1 0/7] Flow API helpers enhancements Adrien Mazarguil
2017-10-05  9:49 ` [dpdk-dev] [PATCH v1 1/7] ethdev: expose flow API error helper Adrien Mazarguil
2017-10-11  9:23   ` Thomas Monjalon
2017-10-11 11:56     ` Adrien Mazarguil
2017-10-11 19:05       ` Aaron Conole
2017-10-12 13:37         ` Neil Horman
2017-10-12 14:02         ` Adrien Mazarguil
2017-10-05  9:49 ` [dpdk-dev] [PATCH v1 2/7] ethdev: replace flow API object copy function Adrien Mazarguil
2017-10-05  9:49 ` [dpdk-dev] [PATCH v1 3/7] ethdev: add flow API item/action name conversion Adrien Mazarguil
2017-10-05  9:49 ` [dpdk-dev] [PATCH v1 4/7] app/testpmd: rely on flow API conversion function Adrien Mazarguil
2017-10-05  9:49 ` [dpdk-dev] [PATCH v1 5/7] ethdev: enhance flow API item/action descriptions Adrien Mazarguil
2017-10-05  9:49 ` [dpdk-dev] [PATCH v1 6/7] ethdev: generate flow API conversion header Adrien Mazarguil
2017-10-05  9:49 ` [dpdk-dev] [PATCH v1 7/7] ethdev: update " Adrien Mazarguil
2017-10-06  1:13 ` [dpdk-dev] [PATCH v1 0/7] Flow API helpers enhancements Ferruh Yigit
2017-10-06  8:05   ` Adrien Mazarguil
2017-10-10 18:05     ` Ferruh Yigit
2017-10-11  9:57       ` Adrien Mazarguil
2017-10-11 18:07         ` Ferruh Yigit
2017-10-12 12:53           ` Adrien Mazarguil
2017-10-12 16:37             ` Ferruh Yigit
2017-10-13 10:42               ` Adrien Mazarguil
2018-08-03 13:36 ` [dpdk-dev] [PATCH v2 0/7] ethdev: add flow API object converter Adrien Mazarguil
2018-08-03 13:36   ` Adrien Mazarguil [this message]
2018-08-03 13:36   ` [dpdk-dev] [PATCH v2 2/7] ethdev: add flow API item/action name conversion Adrien Mazarguil
2018-08-03 13:36   ` [dpdk-dev] [PATCH v2 3/7] app/testpmd: rely on flow API conversion function Adrien Mazarguil
2018-08-03 13:36   ` [dpdk-dev] [PATCH v2 4/7] net/failsafe: switch to flow API object " Adrien Mazarguil
2018-08-03 13:36   ` [dpdk-dev] [PATCH v2 5/7] net/bonding: " Adrien Mazarguil
2018-08-03 13:36   ` [dpdk-dev] [PATCH v2 6/7] ethdev: deprecate rte_flow_copy function Adrien Mazarguil
2018-08-03 13:36   ` [dpdk-dev] [PATCH v2 7/7] ethdev: add missing item/actions to flow object converter Adrien Mazarguil
2018-08-03 14:06   ` [dpdk-dev] [PATCH v2 0/7] ethdev: add flow API " Thomas Monjalon
2018-08-23 13:48   ` Ferruh Yigit
2018-08-27 15:14     ` Adrien Mazarguil
2018-08-24 10:58   ` Ferruh Yigit
2018-08-27 14:12     ` Adrien Mazarguil
2018-08-31  9:00   ` [dpdk-dev] [PATCH v3 " Adrien Mazarguil
2018-08-31  9:01     ` [dpdk-dev] [PATCH v3 1/7] " Adrien Mazarguil
2018-08-31  9:01     ` [dpdk-dev] [PATCH v3 2/7] ethdev: add flow API item/action name conversion Adrien Mazarguil
2018-08-31  9:01     ` [dpdk-dev] [PATCH v3 3/7] app/testpmd: rely on flow API conversion function Adrien Mazarguil
2018-08-31  9:01     ` [dpdk-dev] [PATCH v3 4/7] net/failsafe: switch to flow API object " Adrien Mazarguil
2018-08-31  9:01     ` [dpdk-dev] [PATCH v3 5/7] net/bonding: " Adrien Mazarguil
2018-08-31  9:01     ` [dpdk-dev] [PATCH v3 6/7] ethdev: add missing items/actions to flow object converter Adrien Mazarguil
2018-08-31  9:01     ` [dpdk-dev] [PATCH v3 7/7] ethdev: deprecate rte_flow_copy function Adrien Mazarguil
2018-10-04 14:21       ` Ferruh Yigit
2018-08-31 11:32     ` [dpdk-dev] [PATCH v3 0/7] ethdev: add flow API object converter Nélio Laranjeiro
2018-10-03 20:31       ` Thomas Monjalon
2018-10-04 14:25         ` 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=20180803132032.29038-2-adrien.mazarguil@6wind.com \
    --to=adrien.mazarguil@6wind.com \
    --cc=arybchenko@solarflare.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@intel.com \
    --cc=gaetan.rivet@6wind.com \
    --cc=thomas@monjalon.net \
    /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).