[dpdk-dev] [PATCH v1 2/7] ethdev: replace flow API object copy function

Adrien Mazarguil adrien.mazarguil at 6wind.com
Thu Oct 5 11:49:03 CEST 2017


rte_flow_copy() is bound to duplicate flow rule descriptions (attributes,
pattern and list of actions, all at once), however applications sometimes
need more freedom, 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(). This function supports any number of
object conversion operations in an extensible manner.

While rte_flow_copy() could be re-implemented through rte_flow_conv(), it
is removed without prior notice; it is assumed that this function has no
users besides the fail-safe PMD, therefore no effort is made to maintain
it.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil at 6wind.com>
---
 doc/guides/prog_guide/rte_flow.rst      |  19 ++
 drivers/net/failsafe/failsafe_ether.c   |   6 +-
 drivers/net/failsafe/failsafe_flow.c    |  29 ++-
 drivers/net/failsafe/failsafe_private.h |   4 +-
 lib/librte_ether/rte_ethdev_version.map |   1 +
 lib/librte_ether/rte_flow.c             | 296 ++++++++++++++++++---------
 lib/librte_ether/rte_flow.h             | 193 ++++++++++++++---
 7 files changed, 404 insertions(+), 144 deletions(-)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 565a809..5026730 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -1697,6 +1697,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/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index 0c0748f..80f391a 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -257,9 +257,9 @@ fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
 			DEBUG("Creating flow #%" PRIu32, i++);
 			flow->flows[SUB_ID(sdev)] =
 				rte_flow_create(PORT_ID(sdev),
-						&flow->fd->attr,
-						flow->fd->items,
-						flow->fd->actions,
+						flow->fd.attr,
+						flow->fd.pattern,
+						flow->fd.actions,
 						&ferror);
 			ret = rte_errno;
 			if (ret)
diff --git a/drivers/net/failsafe/failsafe_flow.c b/drivers/net/failsafe/failsafe_flow.c
index 153ceee..a568a8b 100644
--- a/drivers/net/failsafe/failsafe_flow.c
+++ b/drivers/net/failsafe/failsafe_flow.c
@@ -31,8 +31,11 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stddef.h>
+#include <string.h>
 #include <sys/queue.h>
 
+#include <rte_errno.h>
 #include <rte_malloc.h>
 #include <rte_tailq.h>
 #include <rte_flow.h>
@@ -46,19 +49,31 @@ fs_flow_allocate(const struct rte_flow_attr *attr,
 		 const struct rte_flow_action *actions)
 {
 	struct rte_flow *flow;
-	size_t fdsz;
+	const struct rte_flow_conv_rule rule = {
+		{ attr }, { items }, { actions },
+	};
+	struct rte_flow_error error;
+	int ret;
 
-	fdsz = rte_flow_copy(NULL, 0, attr, items, actions);
-	flow = rte_zmalloc(NULL,
-			   sizeof(struct rte_flow) + fdsz,
+	ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, &error);
+	if (ret < 0) {
+		ERROR("Unable to compute flow description size (%s): %s",
+		      error.message ? error.message : "unspecified",
+		      strerror(rte_errno));
+		return NULL;
+	}
+	flow = rte_zmalloc(NULL, offsetof(struct rte_flow, fd) + ret,
 			   RTE_CACHE_LINE_SIZE);
 	if (flow == NULL) {
 		ERROR("Could not allocate new flow");
 		return NULL;
 	}
-	flow->fd = (void *)((uintptr_t)flow + sizeof(*flow));
-	if (rte_flow_copy(flow->fd, fdsz, attr, items, actions) != fdsz) {
-		ERROR("Failed to copy flow description");
+	ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &flow->fd, ret, &rule,
+			    &error);
+	if (ret < 0) {
+		ERROR("Failed to copy flow description (%s): %s",
+		      error.message ? error.message : "unspecified",
+		      strerror(rte_errno));
 		rte_free(flow);
 		return NULL;
 	}
diff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h
index d2d92af..f40d649 100644
--- a/drivers/net/failsafe/failsafe_private.h
+++ b/drivers/net/failsafe/failsafe_private.h
@@ -40,6 +40,7 @@
 #include <rte_dev.h>
 #include <rte_ethdev.h>
 #include <rte_devargs.h>
+#include <rte_flow.h>
 
 #define FAILSAFE_DRIVER_NAME "Fail-safe PMD"
 
@@ -82,7 +83,8 @@ struct rte_flow {
 	/* sub_flows */
 	struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS];
 	/* flow description for synchronization */
-	struct rte_flow_desc *fd;
+	struct rte_flow_conv_rule fd;
+	uint8_t fd_data[];
 };
 
 enum dev_state {
diff --git a/lib/librte_ether/rte_ethdev_version.map b/lib/librte_ether/rte_ethdev_version.map
index 07f9e17..673b570 100644
--- a/lib/librte_ether/rte_ethdev_version.map
+++ b/lib/librte_ether/rte_ethdev_version.map
@@ -192,5 +192,6 @@ DPDK_17.11 {
 	global:
 
 	rte_eth_dev_reset;
+	rte_flow_conv;
 
 } DPDK_17.08;
diff --git a/lib/librte_ether/rte_flow.c b/lib/librte_ether/rte_flow.c
index 34ce516..03a4d35 100644
--- a/lib/librte_ether/rte_flow.c
+++ b/lib/librte_ether/rte_flow.c
@@ -299,110 +299,206 @@ flow_action_conf_size(const struct rte_flow_action *action,
 	*pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
 }
 
-/** Store a full rte_flow description. */
-size_t
-rte_flow_copy(struct rte_flow_desc *desc, size_t len,
-	      const struct rte_flow_attr *attr,
-	      const struct rte_flow_item *items,
-	      const struct rte_flow_action *actions)
+/** Internal helper to convert a pattern. */
+static int
+rte_flow_conv_pattern(struct rte_flow_item *dst,
+		      size_t size,
+		      const struct rte_flow_item *src,
+		      unsigned int num,
+		      struct rte_flow_error *error)
 {
-	struct rte_flow_desc *fd = NULL;
-	size_t tmp;
-	size_t pad;
-	size_t off1 = 0;
-	size_t off2 = 0;
-	size_t size = 0;
+	uint8_t *data = NULL;
+	int store = 0;
+	size_t min;
+	size_t off;
+	unsigned int i;
 
 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);
-			flow_item_spec_size(item, &tmp, &pad);
-			if (item->spec) {
-				if (fd)
-					dst->spec = memcpy(fd->data + off2,
-							   item->spec, tmp);
-				off2 += tmp + pad;
-			}
-			if (item->last) {
-				if (fd)
-					dst->last = memcpy(fd->data + off2,
-							   item->last, tmp);
-				off2 += tmp + pad;
-			}
-			if (item->mask) {
-				if (fd)
-					dst->mask = memcpy(fd->data + off2,
-							   item->mask, tmp);
-				off2 += tmp + pad;
-			}
-			off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-		} while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
-		off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
+	for (off = 0, i = 0; !num || i != num; ++i, ++src, ++dst) {
+		size_t spec;
+		size_t pad;
+
+		if ((size_t)src->type >= RTE_DIM(rte_flow_desc_item) ||
+		    !rte_flow_desc_item[src->type].name)
+			goto notsup;
+		if (store)
+			*dst = (struct rte_flow_item){ .type = src->type, };
+		flow_item_spec_size(src, &spec, &pad);
+		if (spec)
+			off = RTE_ALIGN_CEIL(off, sizeof(double));
+		if (src->spec) {
+			if (store)
+				dst->spec = memcpy(data + off, src->spec, spec);
+			off += spec;
+		}
+		if (src->last) {
+			off += pad;
+			if (store)
+				dst->last = memcpy(data + off, src->last, spec);
+			off += spec;
+		}
+		if (src->mask) {
+			off += pad;
+			if (store)
+				dst->mask = memcpy(data + off, src->mask, spec);
+			off += spec;
+		}
+		if (src->type == RTE_FLOW_ITEM_TYPE_END)
+			num = i + 1;
 	}
-	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);
-			flow_action_conf_size(action, &tmp, &pad);
-			if (action->conf) {
-				if (fd)
-					dst->conf = memcpy(fd->data + off2,
-							   action->conf, tmp);
-				off2 += tmp + pad;
-			}
-			off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-		} while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
+	min = RTE_ALIGN_CEIL(sizeof(*src) * num, sizeof(double)) + off;
+	if (store || !size)
+		return min;
+	if (min > size)
+		goto nomem;
+	src -= i;
+	dst -= i;
+	data = (void *)((uintptr_t)dst + min - off);
+	store = 1;
+	goto store;
+notsup:
+	return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, src,
+				  "cannot convert unknown item type");
+nomem:
+	return rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ITEM, src,
+				  "not enough room to store pattern item");
+}
+
+/** Internal helper to convert a list of actions. */
+static int
+rte_flow_conv_actions(struct rte_flow_action *dst,
+		      size_t size,
+		      const struct rte_flow_action *src,
+		      unsigned int num,
+		      struct rte_flow_error *error)
+{
+	uint8_t *data = NULL;
+	int store = 0;
+	size_t min;
+	size_t off;
+	unsigned int i;
+
+store:
+	for (off = 0, i = 0; !num || i != num; ++i, ++src, ++dst) {
+		size_t conf;
+		size_t pad;
+
+		if ((size_t)src->type >= RTE_DIM(rte_flow_desc_action) ||
+		    !rte_flow_desc_action[src->type].name)
+			goto notsup;
+		if (store)
+			*dst = (struct rte_flow_action){ .type = src->type, };
+		flow_action_conf_size(src, &conf, &pad);
+		if (conf)
+			off = RTE_ALIGN_CEIL(off, sizeof(double));
+		if (store && conf)
+			dst->conf = memcpy(data + off, src->conf, conf);
+		off += conf;
+		if (src->type == RTE_FLOW_ACTION_TYPE_END)
+			num = i + 1;
 	}
-	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,
-			.attr = *attr,
-		};
-		tmp -= offsetof(struct rte_flow_desc, data);
-		off2 = tmp + off1;
-		off1 = tmp;
-		goto store;
+	min = RTE_ALIGN_CEIL(sizeof(*src) * num, sizeof(double)) + off;
+	if (store || !size)
+		return min;
+	if (min > size)
+		goto nomem;
+	src -= i;
+	dst -= i;
+	data = (void *)((uintptr_t)dst + min - off);
+	store = 1;
+	goto store;
+notsup:
+	return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
+				  src, "cannot convert unknown action type");
+nomem:
+	return rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ACTION,
+				  src, "not enough room to store action");
+}
+
+/** Internal helper to convert a flow rule description. */
+static int
+rte_flow_conv_rule(struct rte_flow_conv_rule *dst,
+		   size_t size,
+		   const struct rte_flow_conv_rule *src,
+		   struct rte_flow_error *error)
+{
+	size_t min;
+	int ret;
+
+	/* Attributes. */
+	min = RTE_ALIGN_CEIL((uintptr_t)dst + sizeof(*dst),
+			     sizeof(double)) - (uintptr_t)dst;
+	if (size && size < min)
+		goto nomem;
+	if (size) {
+		dst->attr = (void *)((uintptr_t)dst + min);
+		*dst->attr = *src->attr_ro;
+	}
+	/* Pattern. */
+	min = RTE_ALIGN_CEIL((uintptr_t)dst + min + sizeof(*dst->attr),
+			     sizeof(double)) - (uintptr_t)dst;
+	if (size && size < min)
+		goto nomem;
+	ret = rte_flow_conv_pattern((void *)((uintptr_t)dst + min),
+				    size ? size - min : 0,
+				    src->pattern_ro, 0, error);
+	if (ret < 0)
+		return ret;
+	if (size)
+		dst->pattern = (void *)((uintptr_t)dst + min);
+	/* Actions. */
+	min = RTE_ALIGN_CEIL((uintptr_t)dst + min + ret,
+			     sizeof(double)) - (uintptr_t)dst;
+	if (size && size < min)
+		goto nomem;
+	ret = rte_flow_conv_actions((void *)((uintptr_t)dst + min),
+				    size ? size - min : 0,
+				    src->actions_ro, 0, error);
+	if (ret < 0)
+		return ret;
+	if (size)
+		dst->actions = (void *)((uintptr_t)dst + min);
+	return min + ret;
+nomem:
+	return rte_flow_error_set
+		(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+		 "not enough room for alignment padding");
+}
+
+/** 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 && size < sizeof(*attr))
+			return rte_flow_error_set
+				(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ATTR, src,
+				 "not enough room to store attributes");
+		if (size)
+			memcpy(dst, attr, sizeof(*attr));
+		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 0;
+	return rte_flow_error_set
+		(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+		 "unknown object conversion operation");
 }
diff --git a/lib/librte_ether/rte_flow.h b/lib/librte_ether/rte_flow.h
index ec42f02..3d06bdc 100644
--- a/lib/librte_ether/rte_flow.h
+++ b/lib/librte_ether/rte_flow.h
@@ -42,7 +42,10 @@
  * associated actions in hardware through flow rules.
  */
 
+#include <stddef.h>
+
 #include <rte_arp.h>
+#include <rte_common.h>
 #include <rte_errno.h>
 #include <rte_ether.h>
 #include <rte_icmp.h>
@@ -1067,6 +1070,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
@@ -1306,44 +1422,55 @@ rte_flow_error_set(struct rte_flow_error *error,
 }
 
 /**
- * Generic flow representation.
+ * Flow object conversion helper.
  *
- * This form is sufficient to describe an rte_flow independently from any
- * PMD implementation and allows for replayability and identification.
- */
-struct rte_flow_desc {
-	size_t size; /**< Allocated space including data[]. */
-	struct rte_flow_attr attr; /**< Attributes. */
-	struct rte_flow_item *items; /**< Items. */
-	struct rte_flow_action *actions; /**< Actions. */
-	uint8_t data[]; /**< Storage for items/actions. */
-};
-
-/**
- * Copy an rte_flow rule description.
+ * 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.
  *
- * @param[in] fd
- *   Flow rule description.
- * @param[in] len
- *   Total size of allocated data for the flow description.
- * @param[in] attr
- *   Flow rule attributes.
- * @param[in] items
- *   Pattern specification (list terminated by the END pattern item).
- * @param[in] actions
- *   Associated actions (list terminated by the END action).
+ * Note that in most cases, "deep" copies stop at the boundary of the flow
+ * API. Outside objects are not converted and their pointers are copied
+ * unchanged (e.g. the rss_conf field in struct rte_flow_action_rss).
+ *
+ * Since the destination buffer must be large enough, this function works in
+ * a manner reminiscent of snprintf() as described below:
+ *
+ * - If @p size is 0, nothing is converted and @p dst may be a NULL pointer.
+ *
+ * - If @p size is large enough, conversion occurs and @p dst must be
+ *   non-NULL.
+ *
+ * - The returned value, if positive, is the number of bytes needed to store
+ *   the conversion of @p src in @p dst according to @p op.
+ *
+ * - Otherwise in case of error (e.g. @p size nonzero but not large enough),
+ *   a negative error code is returned.
+ *
+ * @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. Its type may differ from that of @p dst.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. It is initialized in case
+ *   of error only.
  *
  * @return
- *   If len is greater or equal to the size of the flow, the total size of the
- *   flow description and its data.
- *   If len is lower than the size of the flow, the number of bytes that would
- *   have been written to desc had it been sufficient. Nothing is written.
+ *   The number of bytes required to convert @p src on success, a negative
+ *   errno value otherwise and rte_errno is set.
+ *
+ * @see
+ *   rte_flow_conv_op
  */
-size_t
-rte_flow_copy(struct rte_flow_desc *fd, size_t len,
-	      const struct rte_flow_attr *attr,
-	      const struct rte_flow_item *items,
-	      const struct rte_flow_action *actions);
+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
 }
-- 
2.1.4



More information about the dev mailing list