From patchwork Fri Aug 31 09:01:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adrien Mazarguil X-Patchwork-Id: 44068 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id BAD874C9D; Fri, 31 Aug 2018 11:01:19 +0200 (CEST) Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by dpdk.org (Postfix) with ESMTP id B87B94C90 for ; Fri, 31 Aug 2018 11:01:17 +0200 (CEST) Received: by mail-wm0-f65.google.com with SMTP id t25-v6so4568239wmi.3 for ; Fri, 31 Aug 2018 02:01:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=g7sdEZQUr7esOW41/mfdEuP/I0JW2i7OXw6w4kCWNtE=; b=ZjyjC2+Iw1cw5R/nLYC0DvYUwrF6Ywb9uxtjd5VeRxcVlEE9ySdZSuBwXJqMg4Tn3X 6IEtwDx8bQjpMRejhzK+34wI4F7GiIxJbzYppMihxCxmWjBhNIPfRvbSF/3WoLt+4lnx aVbg8Oi7Di6D2MGra9Yv6jOaAUqpvgvF3oat3mTM9o98kL34pP/0zYR3Vngvaxlz9yKf VBjK5h5hX1H7GNWmdgU4VZnU2V6XwIA/d7j/DCpdNglFJ+zreybQHdbFEZOlCkaCcmk1 gzrqZJQ7v72kjZZlvbPTo7EROO076i4IXBfM1yGGcAAHTwi5QaURRZnDr2B8S/ZC3xy3 Bipg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=g7sdEZQUr7esOW41/mfdEuP/I0JW2i7OXw6w4kCWNtE=; b=pyqqXUr4Ic4aTlvxEnqpPHd19svVbI2Ns12bQtwthD7m33HK1kydRFvoJ+O726tt2J zuxcnHj5hN6bmeS8EtJI/YupjmBkyhZS3TNWJZ/M/nz/nfAkoaeahAUVPlDAbFg/1BWK C2ZGUYdGKoK4MhryERHgJSi22pcMjop8+f3ZFopMnoYy7Y527EWUV9il4HFwmzXBFETy VXxhx+VWM+HXUcTv02UtBMCu53NhUt+u4bHNggXSkMwmoyzNku1aEOF8e/brJGUoTieM EaLOhRIZ3fCAHUu7VsFow+W4CBy0GsnwnLbO15lxKCOdZNb/6y0P176UpHmwAwAOUAcv Kgbw== X-Gm-Message-State: APzg51BUl8IPoXZYQvCTF2B2D2Kro7SHLiWqVisJd2qx54+fLSgv6TaM ZsyMiY3UpyoLBxR2FBf6QjxBLQ== X-Google-Smtp-Source: ANB0VdaEmyORj5Wtv0/nWzb+zcVm7n6pLReldnX9N6G+Qq4VYoSGgKEUuO3oFLFsy8gFk7YgchvGYQ== X-Received: by 2002:a1c:c642:: with SMTP id w63-v6mr2146567wmf.3.1535706077149; Fri, 31 Aug 2018 02:01:17 -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 h82-v6sm3198390wme.11.2018.08.31.02.01.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Aug 2018 02:01:16 -0700 (PDT) Date: Fri, 31 Aug 2018 11:01:00 +0200 From: Adrien Mazarguil To: Ferruh Yigit Cc: dev@dpdk.org, Thomas Monjalon , Andrew Rybchenko , Gaetan Rivet Message-ID: <20180831085337.21419-2-adrien.mazarguil@6wind.com> References: <20180803132032.29038-1-adrien.mazarguil@6wind.com> <20180831085337.21419-1-adrien.mazarguil@6wind.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20180831085337.21419-1-adrien.mazarguil@6wind.com> X-Mailer: git-send-email 2.11.0 Subject: [dpdk-dev] [PATCH v3 1/7] ethdev: add flow API object converter 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: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 Cc: Thomas Monjalon Cc: Ferruh Yigit Cc: Andrew Rybchenko Cc: Gaetan Rivet --- v3 changes: - Worked around compilation issue on ARM where rte_memcpy() is a macro that chokes on commas. - Marked rte_flow_conv() as experimental. 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 | 170 +++++++- 4 files changed, 582 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..2ee9173a1 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -239,6 +239,7 @@ EXPERIMENTAL { rte_eth_dev_tx_offload_name; rte_eth_switch_domain_alloc; rte_eth_switch_domain_free; + rte_flow_conv; rte_flow_expand_rss; rte_mtr_capabilities_get; rte_mtr_create; diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c index cff4b5209..4fd6cfa76 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..1288e76ae 100644 --- a/lib/librte_ethdev/rte_flow.h +++ b/lib/librte_ethdev/rte_flow.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -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,54 @@ 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 + */ +__rte_experimental +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