From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by dpdk.org (Postfix) with ESMTP id AB537235 for ; Mon, 28 May 2018 15:34:06 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 May 2018 06:34:05 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,452,1520924400"; d="scan'208";a="42792713" Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by fmsmga007.fm.intel.com with ESMTP; 28 May 2018 06:34:05 -0700 Received: from fmsmsx124.amr.corp.intel.com (10.18.125.39) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.319.2; Mon, 28 May 2018 06:34:03 -0700 Received: from fmsmsx117.amr.corp.intel.com ([169.254.3.45]) by fmsmsx124.amr.corp.intel.com ([169.254.8.182]) with mapi id 14.03.0319.002; Mon, 28 May 2018 06:33:30 -0700 From: "Wiles, Keith" To: Nelio Laranjeiro CC: "dev@dpdk.org" , Adrien Mazarguil Thread-Topic: [dpdk-dev] [DPDK 18.08] ethdev: add flow API to expand RSS flows Thread-Index: AQHT9mn0Ft01AJm1qUKbnkydSOTPH6RFmW+A Date: Mon, 28 May 2018 13:33:29 +0000 Message-ID: References: In-Reply-To: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.254.78.16] Content-Type: text/plain; charset="us-ascii" Content-ID: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [DPDK 18.08] ethdev: add flow API to expand RSS flows 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: Mon, 28 May 2018 13:34:07 -0000 This one too is missing the [PATCH ] keyword in the subject line. > On May 28, 2018, at 4:54 AM, Nelio Laranjeiro wrote: >=20 > Introduce an helper for PMD to expand easily flows items list with RSS > action into multiple flow items lists with priority information. >=20 > For instance a user items list being "eth / end" with rss action types > "ipv4-udp ipv6-udp end" needs to be expanded into three items lists: >=20 > - eth > - eth / ipv4 / udp > - eth / ipv6 / udp >=20 > to match the user request. Some drivers are unable to reach such > request without this expansion, this API is there to help those. > Only PMD should use such API for their internal cooking, the application > will still handle a single flow. >=20 > Signed-off-by: Nelio Laranjeiro > --- > lib/librte_ethdev/rte_flow.c | 404 ++++++++++++++++++++++++++++ > lib/librte_ethdev/rte_flow_driver.h | 32 +++ > 2 files changed, 436 insertions(+) >=20 > diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c > index 7947529da..0c42fc31c 100644 > --- a/lib/librte_ethdev/rte_flow.c > +++ b/lib/librte_ethdev/rte_flow.c > @@ -507,3 +507,407 @@ rte_flow_copy(struct rte_flow_desc *desc, size_t le= n, > } > return 0; > } > + > +/* Copy the existing items list and expand with new items. */ > +static int > +rte_flow_expand_rss_item(void *buf, size_t size, > + const struct rte_flow_item *items, > + const struct rte_flow_item *newitems) > +{ > + void *data =3D buf; > + const struct rte_flow_item *item; > + struct rte_flow_item *dst; > + size_t data_size =3D 0; > + > + dst =3D data; > + /* Copy Item structure into buffer. */ > + for (item =3D items; item->type !=3D RTE_FLOW_ITEM_TYPE_END; ++item) { > + if (item->type =3D=3D RTE_FLOW_ITEM_TYPE_VOID) > + continue; > + if (data_size + sizeof(*item) <=3D size) { > + memcpy(dst, item, sizeof(*item)); > + ++dst; > + } > + data_size +=3D sizeof(*item); > + } > + item =3D newitems; > + do { > + if (item->type =3D=3D RTE_FLOW_ITEM_TYPE_VOID) { > + ++item; > + continue; > + } > + if (data_size + sizeof(*item) <=3D size) { > + memcpy(dst, item, sizeof(*item)); > + ++dst; > + } > + data_size +=3D sizeof(*item); > + ++item; > + } while ((item - 1)->type !=3D RTE_FLOW_ITEM_TYPE_END); > + /** > + * Copy Item spec, last, mask into buffer and set pointers > + * accordingly. > + */ > + dst =3D data; > + for (item =3D items; item->type !=3D RTE_FLOW_ITEM_TYPE_END; ++item) { > + if (item->type =3D=3D RTE_FLOW_ITEM_TYPE_VOID) > + continue; > + if (item->spec) { > + size_t s =3D flow_item_spec_copy(NULL, item, ITEM_SPEC); > + void *addr =3D (data_size + s) <=3D size ? > + (void *)((uintptr_t)data + data_size) : > + NULL; > + > + data_size +=3D flow_item_spec_copy(addr, item, ITEM_SPEC); > + if (addr) > + dst->spec =3D addr; > + } > + if (item->last) { > + size_t s =3D flow_item_spec_copy(NULL, item, ITEM_LAST); > + void *addr =3D (data_size + s) <=3D size ? > + (void *)((uintptr_t)data + data_size) : > + NULL; > + > + data_size +=3D flow_item_spec_copy(addr, item, ITEM_LAST); > + if (addr) > + dst->last =3D addr; > + } > + if (item->mask) { > + size_t s =3D flow_item_spec_copy(NULL, item, ITEM_MASK); > + void *addr =3D (data_size + s) <=3D size ? > + (void *)((uintptr_t)data + data_size) : > + NULL; > + > + data_size +=3D flow_item_spec_copy(addr, item, ITEM_MASK); > + if (addr) > + dst->mask =3D addr; > + } > + if (data_size <=3D size) > + ++dst; > + } > + return data_size; > +} > + > +/** Verify the expansion is supported by the device. */ > +static int > +rte_flow_expand_rss_is_supported(const enum rte_flow_item_type **support= ed, > + const enum rte_flow_item_type *expand) > +{ > + unsigned int i; > + unsigned int sidx; > + unsigned int eidx; > + > + for (i =3D 0; supported[i]; ++i) { > + sidx =3D 0; > + eidx =3D 0; > + while (1) { > + if (expand[eidx] !=3D supported[i][sidx]) { > + break; > + } else if ((expand[eidx] =3D=3D RTE_FLOW_ITEM_TYPE_END) && > + (supported[i][sidx] =3D=3D > + RTE_FLOW_ITEM_TYPE_END)) { > + return 1; > + } else if ((expand[eidx] =3D=3D RTE_FLOW_ITEM_TYPE_END) || > + (supported[i][sidx] =3D=3D > + RTE_FLOW_ITEM_TYPE_END)) { > + break; > + } else if (expand[eidx] =3D=3D RTE_FLOW_ITEM_TYPE_VOID) { > + ++eidx; > + continue; > + } else if (supported[i][sidx] =3D=3D > + RTE_FLOW_ITEM_TYPE_VOID) { > + ++sidx; > + continue; > + } > + ++sidx; > + ++eidx; > + } > + } > + return 0; > +} > + > +/** Update internal buffer. */ > +static inline void > +rte_flow_expand_rss_update(struct rte_flow_expand_rss *buf, void *addr, > + uint32_t priority) > +{ > + buf->priority[buf->entries] =3D priority; > + buf->patterns[buf->entries] =3D addr; > + buf->entries++; > +} > + > +int > +rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, > + const struct rte_flow_item *pat, uint64_t types, > + const enum rte_flow_item_type **supported) > +{ > + const struct rte_flow_item *item; > + uint32_t priority =3D 0; > + struct { > + uint32_t eth:1; /**< Ethernet item is present. */ > + uint32_t ipv4:1; /**< IPv4 item is present. */ > + uint32_t ipv6:1; /**< IPv6 item is present. */ > + uint32_t ipv6_ex:1; /**< IPv6 EXT item is present. */ > + uint32_t udp:1; /**< UDP item is present. */ > + uint32_t tcp:1; /**< TCP item is present. */ > + uint32_t sctp:1; /**< STCP item is present. */ > + uint32_t vxlan:1; /**< VXLAN item is present. */ > + uint32_t geneve:1; /**< GENEVE item is present. */ > + uint32_t nvgre:1; /**< NVGRE item is present. */ > + } layer =3D { .eth =3D 0 }; > + const struct rte_flow_item end[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + void *addr; > + uint32_t off; /**< Offset to write new items data starting from *buf. *= / > + uint32_t max_entries; > + > + for (max_entries =3D 0; supported[max_entries]; ++max_entries) > + ; > + off =3D sizeof(*buf) + > + /* Size for the list of patterns. */ > + sizeof(*buf->patterns) + > + RTE_ALIGN_CEIL(max_entries * sizeof(struct rte_flow_item *), > + sizeof(void *)) + > + /* Size for priorities. */ > + sizeof(*buf->priority) + > + RTE_ALIGN_CEIL(max_entries * sizeof(uint32_t), sizeof(void *)); > + if (off < size) { > + buf->priority =3D (void *)(buf + 1); > + buf->patterns =3D (void *)&buf->priority[max_entries]; > + buf->patterns[0] =3D (void *)&buf->patterns[max_entries]; > + addr =3D buf->patterns[0]; > + buf->entries =3D 0; > + } > + /** > + * Parse the pattern and deactivate the bit-field in RSS which cannot > + * match anymore the pattern. > + */ > + for (item =3D pat; item->type !=3D RTE_FLOW_ITEM_TYPE_END; ++item) { > + switch (item->type) { > + case RTE_FLOW_ITEM_TYPE_ETH: > + layer.eth =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_IPV4: > + layer.ipv4 =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_IPV6: > + layer.ipv6 =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_IPV6_EXT: > + layer.ipv6_ex =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_UDP: > + layer.udp =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_TCP: > + layer.tcp =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_VXLAN: > + layer.vxlan =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_GENEVE: > + layer.geneve =3D 1; > + break; > + case RTE_FLOW_ITEM_TYPE_NVGRE: > + layer.nvgre =3D 1; > + break; > + default: > + break; > + } > + } > + off +=3D rte_flow_expand_rss_item(addr, (off < size) ? size - off : 0, > + pat, end); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + if ((types & ETH_RSS_IP) && > + (!(layer.ipv4 || layer.ipv6 || layer.ipv6_ex))) { > + ++priority; > + if (types & (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 | > + ETH_RSS_NONFRAG_IPV4_OTHER)) { > + const struct rte_flow_item new[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_IPV4 }, > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + const enum rte_flow_item_type list[] =3D { > + RTE_FLOW_ITEM_TYPE_ETH, > + RTE_FLOW_ITEM_TYPE_IPV4, > + RTE_FLOW_ITEM_TYPE_END, > + }; > + int ret; > + > + ret =3D rte_flow_expand_rss_is_supported(supported, list); > + if (ret) { > + off +=3D rte_flow_expand_rss_item > + (addr, (off <=3D size) ? size - off : 0, > + pat, new); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, > + priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + } > + } > + if (types & (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 | > + ETH_RSS_NONFRAG_IPV6_OTHER)) { > + const struct rte_flow_item new[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_IPV6 }, > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + const enum rte_flow_item_type list[] =3D { > + RTE_FLOW_ITEM_TYPE_ETH, > + RTE_FLOW_ITEM_TYPE_IPV6, > + RTE_FLOW_ITEM_TYPE_END, > + }; > + int ret; > + > + ret =3D rte_flow_expand_rss_is_supported(supported, list); > + if (ret) { > + off +=3D rte_flow_expand_rss_item > + (addr, (size < off) ? size - off : 0, > + pat, new); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, > + priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + } > + } > + if (types & ETH_RSS_IPV6_EX) { > + const struct rte_flow_item new[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_IPV6_EXT }, > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + const enum rte_flow_item_type list[] =3D { > + RTE_FLOW_ITEM_TYPE_ETH, > + RTE_FLOW_ITEM_TYPE_IPV6_EXT, > + RTE_FLOW_ITEM_TYPE_END, > + }; > + int ret; > + > + ret =3D rte_flow_expand_rss_is_supported(supported, list); > + if (ret) { > + off +=3D rte_flow_expand_rss_item > + (addr, (off <=3D size) ? size - off : 0, > + pat, new); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, > + priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + } > + } > + } > + if (types & (ETH_RSS_TCP | ETH_RSS_UDP)) { > + ++priority; > + if ((types & ETH_RSS_NONFRAG_IPV4_UDP) && > + !(layer.ipv6 || layer.ipv6_ex || layer.tcp || layer.udp)) { > + const struct rte_flow_item new[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_UDP }, > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + const enum rte_flow_item_type list[] =3D { > + RTE_FLOW_ITEM_TYPE_ETH, > + RTE_FLOW_ITEM_TYPE_IPV4, > + RTE_FLOW_ITEM_TYPE_UDP, > + RTE_FLOW_ITEM_TYPE_END, > + }; > + int ret; > + > + ret =3D rte_flow_expand_rss_is_supported(supported, list); > + if (ret) { > + off +=3D rte_flow_expand_rss_item > + (addr, (off <=3D size) ? size - off : 0, > + pat, new); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, > + priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + } > + } > + if ((types & ETH_RSS_NONFRAG_IPV4_TCP) && > + !(layer.ipv6 || layer.ipv6_ex || layer.tcp || layer.udp)) { > + const struct rte_flow_item new[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_TCP }, > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + const enum rte_flow_item_type list[] =3D { > + RTE_FLOW_ITEM_TYPE_ETH, > + RTE_FLOW_ITEM_TYPE_IPV4, > + RTE_FLOW_ITEM_TYPE_TCP, > + RTE_FLOW_ITEM_TYPE_END, > + }; > + int ret; > + > + ret =3D rte_flow_expand_rss_is_supported(supported, list); > + if (ret) { > + off +=3D rte_flow_expand_rss_item > + (addr, (off <=3D size) ? size - off : 0, > + pat, new); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, > + priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + } > + } > + if ((types & ETH_RSS_NONFRAG_IPV6_UDP) && > + !(layer.ipv4 || layer.tcp || layer.udp)) { > + const struct rte_flow_item new[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_UDP }, > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + const enum rte_flow_item_type list[] =3D { > + RTE_FLOW_ITEM_TYPE_ETH, > + RTE_FLOW_ITEM_TYPE_IPV6, > + RTE_FLOW_ITEM_TYPE_UDP, > + RTE_FLOW_ITEM_TYPE_END, > + }; > + int ret; > + > + ret =3D rte_flow_expand_rss_is_supported(supported, list); > + if (ret) { > + off +=3D rte_flow_expand_rss_item > + (addr, (size < off) ? size - off : 0, > + pat, new); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, > + priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + } > + } > + if ((types & (ETH_RSS_NONFRAG_IPV6_TCP | > + ETH_RSS_IPV6_TCP_EX)) && > + !(layer.ipv4 || layer.tcp || layer.udp)) { > + const struct rte_flow_item new[] =3D { > + { .type =3D RTE_FLOW_ITEM_TYPE_TCP }, > + { .type =3D RTE_FLOW_ITEM_TYPE_END }, > + }; > + const enum rte_flow_item_type list[] =3D { > + RTE_FLOW_ITEM_TYPE_ETH, > + (layer.ipv6_ex ? > + RTE_FLOW_ITEM_TYPE_IPV6_EXT : > + RTE_FLOW_ITEM_TYPE_IPV6), > + RTE_FLOW_ITEM_TYPE_UDP, > + RTE_FLOW_ITEM_TYPE_END, > + }; > + int ret; > + > + ret =3D rte_flow_expand_rss_is_supported(supported, list); > + if (ret) { > + off +=3D rte_flow_expand_rss_item > + (addr, (off < size) ? size - off : 0, > + pat, new); > + if (off <=3D size) { > + rte_flow_expand_rss_update(buf, addr, > + priority); > + addr =3D (void *)((uintptr_t)buf + off); > + } > + } > + } > + } > + return off; > +} > diff --git a/lib/librte_ethdev/rte_flow_driver.h b/lib/librte_ethdev/rte_= flow_driver.h > index 1c90c600d..9058a8715 100644 > --- a/lib/librte_ethdev/rte_flow_driver.h > +++ b/lib/librte_ethdev/rte_flow_driver.h > @@ -114,6 +114,38 @@ struct rte_flow_ops { > const struct rte_flow_ops * > rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error); >=20 > +/** > + * Expansion structure for RSS flows. > + */ > +struct rte_flow_expand_rss { > + uint32_t entries; /**< Number of entries in the following arrays. */ > + struct rte_flow_item **patterns; /**< Expanded pattern array. */ > + uint32_t *priority; /**< Priority offset for each expansion. */ > +}; > + > +/** > + * Expand RSS flows into several possible flows according to the RSS has= h > + * fields requested and the driver capabilities. > + * > + * @param[in,out] buf > + * Buffer to store the result expansion. > + * @param[in] size > + * Size in octets of the buffer. > + * @param[in] pat > + * User flow pattern. > + * @param[in] types > + * RSS types expected (see ETH_RSS_*). > + * @param[in] supported. > + * List of support expansion pattern from the device. > + * > + * @return > + * The size in octets used to expand. > + */ > +int > +rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size, > + const struct rte_flow_item *pat, uint64_t types, > + const enum rte_flow_item_type **supported); > + > #ifdef __cplusplus > } > #endif > --=20 > 2.17.0 >=20 Regards, Keith