From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr0-f172.google.com (mail-wr0-f172.google.com [209.85.128.172]) by dpdk.org (Postfix) with ESMTP id 526AB1B199 for ; Thu, 5 Oct 2017 11:49:23 +0200 (CEST) Received: by mail-wr0-f172.google.com with SMTP id y44so2737511wry.10 for ; Thu, 05 Oct 2017 02:49:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=y1+lbA8NeMbISTPvgq6cSI22YKz85teaADtnsgc8k2I=; b=xIwP8IvztgwOW1dukp/yHpckiD6BZUpAXpp5RymIUlt3Sk1GZEsZrrzwC8rykKcSng QqywAk4oRowGO1BvfnTARY+vzhZxxCG9UAJ6pHvTFbN5mfwgdWHdJTRayEC2rwp85OFe AP/eOp3/XvpNVGo3Uk9phcrR//3ouxJVsPH/fA1V8hwpyIRFK2hM/sjMfQeU+aFbWZhi 66Va2mGpleFZMuactrHxrR15liTbgdDZEzg1dvvChHQcWVHGBbXNVuvpHvAr2ffI/BLR I6EpmtUOKPmYD+YYy0/XVDbU2PmYgkrJU3X73pnjMF7yLwb0Qyik31oXYdYMdq6sW2rD Otug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=y1+lbA8NeMbISTPvgq6cSI22YKz85teaADtnsgc8k2I=; b=GLZZFzjOmaHQzVltCIsO0NZJNrBjeSCY00mhQ+EiSrsHVf03c9J5eMqqz27hjOVCWm a0OVxibiz8SFqjAulZVLRhe0d6Fufo7V1BkpGpMSCwbI8BPrwKelz7FI+vCZDFPse5sB 25IUFO8c0EFTH1+OhV0Iw9Y0vC+ACxCHqHRMkWDuYKSjb7i2TUnlNt5y+AVBOmYwFd07 6+fEGARyHOMi6ZjcB9UZMSvMlY1zC//OmbIpcAvn1Zmee8MNzv5obxJKHf3l44GKpiKZ 4HgUAnnrFFJiLt/jmT0dXAQfXdeZJBq0hsbC1T9YX4Xuy7iwJ/PgAOvYROaC7T3TZa5k DtDg== X-Gm-Message-State: AMCzsaUSXk2wQyaU7j7CXBvV6BhSvQOb6OHYnmg/Un98+Y0EbYQ4bduM VM3tisTFddqmjo/FoQ1pIM6F9iy+ X-Google-Smtp-Source: AOwi7QDGaSEma9GOjPQ67GfEXCVi0fp0oFSeHjfmqwgHNyvWyd5r8b78G/6rglaNDl/9k+32MQCWEg== X-Received: by 10.223.150.194 with SMTP id u60mr7474677wrb.141.1507196962740; Thu, 05 Oct 2017 02:49:22 -0700 (PDT) Received: from 6wind.com (host.78.145.23.62.rev.coltfrance.com. [62.23.145.78]) by smtp.gmail.com with ESMTPSA id 4sm23841956wmm.1.2017.10.05.02.49.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 05 Oct 2017 02:49:21 -0700 (PDT) From: Adrien Mazarguil To: Ferruh Yigit , Gaetan Rivet Cc: dev@dpdk.org Date: Thu, 5 Oct 2017 11:49:03 +0200 Message-Id: <235baf6b9798cd1d038f06d473498ed7359907d8.1507193186.git.adrien.mazarguil@6wind.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: References: Subject: [dpdk-dev] [PATCH v1 2/7] ethdev: replace flow API object copy function 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: , X-List-Received-Date: Thu, 05 Oct 2017 09:49:24 -0000 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 --- 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 +#include #include +#include #include #include #include @@ -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 #include #include +#include #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 + #include +#include #include #include #include @@ -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