@@ -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
-------
@@ -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)
@@ -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;
}
@@ -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 {
@@ -192,5 +192,6 @@ DPDK_17.11 {
global:
rte_eth_dev_reset;
+ rte_flow_conv;
} DPDK_17.08;
@@ -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");
}
@@ -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
}