199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2017 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <rte_malloc.h>
699a2dd95SBruce Richardson #include <rte_cycles.h>
799a2dd95SBruce Richardson #include <rte_ethdev.h>
899a2dd95SBruce Richardson
999a2dd95SBruce Richardson #include "rte_gro.h"
1099a2dd95SBruce Richardson #include "gro_tcp4.h"
11*74080d7dSKumara Parameshwaran #include "gro_tcp6.h"
1299a2dd95SBruce Richardson #include "gro_udp4.h"
1399a2dd95SBruce Richardson #include "gro_vxlan_tcp4.h"
1499a2dd95SBruce Richardson #include "gro_vxlan_udp4.h"
1599a2dd95SBruce Richardson
1699a2dd95SBruce Richardson typedef void *(*gro_tbl_create_fn)(uint16_t socket_id,
1799a2dd95SBruce Richardson uint16_t max_flow_num,
1899a2dd95SBruce Richardson uint16_t max_item_per_flow);
1999a2dd95SBruce Richardson typedef void (*gro_tbl_destroy_fn)(void *tbl);
2099a2dd95SBruce Richardson typedef uint32_t (*gro_tbl_pkt_count_fn)(void *tbl);
2199a2dd95SBruce Richardson
2299a2dd95SBruce Richardson static gro_tbl_create_fn tbl_create_fn[RTE_GRO_TYPE_MAX_NUM] = {
2399a2dd95SBruce Richardson gro_tcp4_tbl_create, gro_vxlan_tcp4_tbl_create,
24*74080d7dSKumara Parameshwaran gro_udp4_tbl_create, gro_vxlan_udp4_tbl_create, gro_tcp6_tbl_create, NULL};
2599a2dd95SBruce Richardson static gro_tbl_destroy_fn tbl_destroy_fn[RTE_GRO_TYPE_MAX_NUM] = {
2699a2dd95SBruce Richardson gro_tcp4_tbl_destroy, gro_vxlan_tcp4_tbl_destroy,
2799a2dd95SBruce Richardson gro_udp4_tbl_destroy, gro_vxlan_udp4_tbl_destroy,
28*74080d7dSKumara Parameshwaran gro_tcp6_tbl_destroy,
2999a2dd95SBruce Richardson NULL};
3099a2dd95SBruce Richardson static gro_tbl_pkt_count_fn tbl_pkt_count_fn[RTE_GRO_TYPE_MAX_NUM] = {
3199a2dd95SBruce Richardson gro_tcp4_tbl_pkt_count, gro_vxlan_tcp4_tbl_pkt_count,
3299a2dd95SBruce Richardson gro_udp4_tbl_pkt_count, gro_vxlan_udp4_tbl_pkt_count,
33*74080d7dSKumara Parameshwaran gro_tcp6_tbl_pkt_count,
3499a2dd95SBruce Richardson NULL};
3599a2dd95SBruce Richardson
3699a2dd95SBruce Richardson #define IS_IPV4_TCP_PKT(ptype) (RTE_ETH_IS_IPV4_HDR(ptype) && \
3799a2dd95SBruce Richardson ((ptype & RTE_PTYPE_L4_TCP) == RTE_PTYPE_L4_TCP) && \
38bdf2f895SKumara Parameshwaran ((ptype & RTE_PTYPE_L4_FRAG) != RTE_PTYPE_L4_FRAG) && \
3999a2dd95SBruce Richardson (RTE_ETH_IS_TUNNEL_PKT(ptype) == 0))
4099a2dd95SBruce Richardson
41*74080d7dSKumara Parameshwaran /* GRO with extension headers is not supported */
42*74080d7dSKumara Parameshwaran #define IS_IPV6_TCP_PKT(ptype) (RTE_ETH_IS_IPV6_HDR(ptype) && \
43*74080d7dSKumara Parameshwaran ((ptype & RTE_PTYPE_L4_TCP) == RTE_PTYPE_L4_TCP) && \
44*74080d7dSKumara Parameshwaran ((ptype & RTE_PTYPE_L4_FRAG) != RTE_PTYPE_L4_FRAG) && \
45*74080d7dSKumara Parameshwaran (RTE_ETH_IS_TUNNEL_PKT(ptype) == 0))
46*74080d7dSKumara Parameshwaran
4799a2dd95SBruce Richardson #define IS_IPV4_UDP_PKT(ptype) (RTE_ETH_IS_IPV4_HDR(ptype) && \
4899a2dd95SBruce Richardson ((ptype & RTE_PTYPE_L4_UDP) == RTE_PTYPE_L4_UDP) && \
4999a2dd95SBruce Richardson (RTE_ETH_IS_TUNNEL_PKT(ptype) == 0))
5099a2dd95SBruce Richardson
5199a2dd95SBruce Richardson #define IS_IPV4_VXLAN_TCP4_PKT(ptype) (RTE_ETH_IS_IPV4_HDR(ptype) && \
5299a2dd95SBruce Richardson ((ptype & RTE_PTYPE_L4_UDP) == RTE_PTYPE_L4_UDP) && \
53bdf2f895SKumara Parameshwaran ((ptype & RTE_PTYPE_L4_FRAG) != RTE_PTYPE_L4_FRAG) && \
5499a2dd95SBruce Richardson ((ptype & RTE_PTYPE_TUNNEL_VXLAN) == \
5599a2dd95SBruce Richardson RTE_PTYPE_TUNNEL_VXLAN) && \
5699a2dd95SBruce Richardson ((ptype & RTE_PTYPE_INNER_L4_TCP) == \
5799a2dd95SBruce Richardson RTE_PTYPE_INNER_L4_TCP) && \
5899a2dd95SBruce Richardson (((ptype & RTE_PTYPE_INNER_L3_MASK) == \
5999a2dd95SBruce Richardson RTE_PTYPE_INNER_L3_IPV4) || \
6099a2dd95SBruce Richardson ((ptype & RTE_PTYPE_INNER_L3_MASK) == \
6199a2dd95SBruce Richardson RTE_PTYPE_INNER_L3_IPV4_EXT) || \
6299a2dd95SBruce Richardson ((ptype & RTE_PTYPE_INNER_L3_MASK) == \
6399a2dd95SBruce Richardson RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN)))
6499a2dd95SBruce Richardson
6599a2dd95SBruce Richardson #define IS_IPV4_VXLAN_UDP4_PKT(ptype) (RTE_ETH_IS_IPV4_HDR(ptype) && \
6699a2dd95SBruce Richardson ((ptype & RTE_PTYPE_L4_UDP) == RTE_PTYPE_L4_UDP) && \
6799a2dd95SBruce Richardson ((ptype & RTE_PTYPE_TUNNEL_VXLAN) == \
6899a2dd95SBruce Richardson RTE_PTYPE_TUNNEL_VXLAN) && \
6999a2dd95SBruce Richardson ((ptype & RTE_PTYPE_INNER_L4_UDP) == \
7099a2dd95SBruce Richardson RTE_PTYPE_INNER_L4_UDP) && \
7199a2dd95SBruce Richardson (((ptype & RTE_PTYPE_INNER_L3_MASK) == \
7299a2dd95SBruce Richardson RTE_PTYPE_INNER_L3_IPV4) || \
7399a2dd95SBruce Richardson ((ptype & RTE_PTYPE_INNER_L3_MASK) == \
7499a2dd95SBruce Richardson RTE_PTYPE_INNER_L3_IPV4_EXT) || \
7599a2dd95SBruce Richardson ((ptype & RTE_PTYPE_INNER_L3_MASK) == \
7699a2dd95SBruce Richardson RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN)))
7799a2dd95SBruce Richardson
7899a2dd95SBruce Richardson /*
7999a2dd95SBruce Richardson * GRO context structure. It keeps the table structures, which are
8099a2dd95SBruce Richardson * used to merge packets, for different GRO types. Before using
8199a2dd95SBruce Richardson * rte_gro_reassemble(), applications need to create the GRO context
8299a2dd95SBruce Richardson * first.
8399a2dd95SBruce Richardson */
8499a2dd95SBruce Richardson struct gro_ctx {
8599a2dd95SBruce Richardson /* GRO types to perform */
8699a2dd95SBruce Richardson uint64_t gro_types;
8799a2dd95SBruce Richardson /* reassembly tables */
8899a2dd95SBruce Richardson void *tbls[RTE_GRO_TYPE_MAX_NUM];
8999a2dd95SBruce Richardson };
9099a2dd95SBruce Richardson
9199a2dd95SBruce Richardson void *
rte_gro_ctx_create(const struct rte_gro_param * param)9299a2dd95SBruce Richardson rte_gro_ctx_create(const struct rte_gro_param *param)
9399a2dd95SBruce Richardson {
9499a2dd95SBruce Richardson struct gro_ctx *gro_ctx;
9599a2dd95SBruce Richardson gro_tbl_create_fn create_tbl_fn;
9699a2dd95SBruce Richardson uint64_t gro_type_flag = 0;
9799a2dd95SBruce Richardson uint64_t gro_types = 0;
9899a2dd95SBruce Richardson uint8_t i;
9999a2dd95SBruce Richardson
10099a2dd95SBruce Richardson gro_ctx = rte_zmalloc_socket(__func__,
10199a2dd95SBruce Richardson sizeof(struct gro_ctx),
10299a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE,
10399a2dd95SBruce Richardson param->socket_id);
10499a2dd95SBruce Richardson if (gro_ctx == NULL)
10599a2dd95SBruce Richardson return NULL;
10699a2dd95SBruce Richardson
10799a2dd95SBruce Richardson for (i = 0; i < RTE_GRO_TYPE_MAX_NUM; i++) {
10899a2dd95SBruce Richardson gro_type_flag = 1ULL << i;
10999a2dd95SBruce Richardson if ((param->gro_types & gro_type_flag) == 0)
11099a2dd95SBruce Richardson continue;
11199a2dd95SBruce Richardson
11299a2dd95SBruce Richardson create_tbl_fn = tbl_create_fn[i];
11399a2dd95SBruce Richardson if (create_tbl_fn == NULL)
11499a2dd95SBruce Richardson continue;
11599a2dd95SBruce Richardson
11699a2dd95SBruce Richardson gro_ctx->tbls[i] = create_tbl_fn(param->socket_id,
11799a2dd95SBruce Richardson param->max_flow_num,
11899a2dd95SBruce Richardson param->max_item_per_flow);
11999a2dd95SBruce Richardson if (gro_ctx->tbls[i] == NULL) {
12099a2dd95SBruce Richardson /* destroy all created tables */
12199a2dd95SBruce Richardson gro_ctx->gro_types = gro_types;
12299a2dd95SBruce Richardson rte_gro_ctx_destroy(gro_ctx);
12399a2dd95SBruce Richardson return NULL;
12499a2dd95SBruce Richardson }
12599a2dd95SBruce Richardson gro_types |= gro_type_flag;
12699a2dd95SBruce Richardson }
12799a2dd95SBruce Richardson gro_ctx->gro_types = param->gro_types;
12899a2dd95SBruce Richardson
12999a2dd95SBruce Richardson return gro_ctx;
13099a2dd95SBruce Richardson }
13199a2dd95SBruce Richardson
13299a2dd95SBruce Richardson void
rte_gro_ctx_destroy(void * ctx)13399a2dd95SBruce Richardson rte_gro_ctx_destroy(void *ctx)
13499a2dd95SBruce Richardson {
13599a2dd95SBruce Richardson gro_tbl_destroy_fn destroy_tbl_fn;
13699a2dd95SBruce Richardson struct gro_ctx *gro_ctx = ctx;
13799a2dd95SBruce Richardson uint64_t gro_type_flag;
13899a2dd95SBruce Richardson uint8_t i;
13999a2dd95SBruce Richardson
14099a2dd95SBruce Richardson for (i = 0; i < RTE_GRO_TYPE_MAX_NUM; i++) {
14199a2dd95SBruce Richardson gro_type_flag = 1ULL << i;
14299a2dd95SBruce Richardson if ((gro_ctx->gro_types & gro_type_flag) == 0)
14399a2dd95SBruce Richardson continue;
14499a2dd95SBruce Richardson destroy_tbl_fn = tbl_destroy_fn[i];
14599a2dd95SBruce Richardson if (destroy_tbl_fn)
14699a2dd95SBruce Richardson destroy_tbl_fn(gro_ctx->tbls[i]);
14799a2dd95SBruce Richardson }
14899a2dd95SBruce Richardson rte_free(gro_ctx);
14999a2dd95SBruce Richardson }
15099a2dd95SBruce Richardson
15199a2dd95SBruce Richardson uint16_t
rte_gro_reassemble_burst(struct rte_mbuf ** pkts,uint16_t nb_pkts,const struct rte_gro_param * param)15299a2dd95SBruce Richardson rte_gro_reassemble_burst(struct rte_mbuf **pkts,
15399a2dd95SBruce Richardson uint16_t nb_pkts,
15499a2dd95SBruce Richardson const struct rte_gro_param *param)
15599a2dd95SBruce Richardson {
15699a2dd95SBruce Richardson /* allocate a reassembly table for TCP/IPv4 GRO */
15799a2dd95SBruce Richardson struct gro_tcp4_tbl tcp_tbl;
15899a2dd95SBruce Richardson struct gro_tcp4_flow tcp_flows[RTE_GRO_MAX_BURST_ITEM_NUM];
1595c55e819SKumara Parameshwaran struct gro_tcp_item tcp_items[RTE_GRO_MAX_BURST_ITEM_NUM] = {{0} };
16099a2dd95SBruce Richardson
161*74080d7dSKumara Parameshwaran struct gro_tcp6_tbl tcp6_tbl;
162*74080d7dSKumara Parameshwaran struct gro_tcp6_flow tcp6_flows[RTE_GRO_MAX_BURST_ITEM_NUM];
163*74080d7dSKumara Parameshwaran struct gro_tcp_item tcp6_items[RTE_GRO_MAX_BURST_ITEM_NUM] = {{0} };
164*74080d7dSKumara Parameshwaran
16599a2dd95SBruce Richardson /* allocate a reassembly table for UDP/IPv4 GRO */
16699a2dd95SBruce Richardson struct gro_udp4_tbl udp_tbl;
16799a2dd95SBruce Richardson struct gro_udp4_flow udp_flows[RTE_GRO_MAX_BURST_ITEM_NUM];
16899a2dd95SBruce Richardson struct gro_udp4_item udp_items[RTE_GRO_MAX_BURST_ITEM_NUM] = {{0} };
16999a2dd95SBruce Richardson
17099a2dd95SBruce Richardson /* Allocate a reassembly table for VXLAN TCP GRO */
17199a2dd95SBruce Richardson struct gro_vxlan_tcp4_tbl vxlan_tcp_tbl;
17299a2dd95SBruce Richardson struct gro_vxlan_tcp4_flow vxlan_tcp_flows[RTE_GRO_MAX_BURST_ITEM_NUM];
17399a2dd95SBruce Richardson struct gro_vxlan_tcp4_item vxlan_tcp_items[RTE_GRO_MAX_BURST_ITEM_NUM]
17499a2dd95SBruce Richardson = {{{0}, 0, 0} };
17599a2dd95SBruce Richardson
17699a2dd95SBruce Richardson /* Allocate a reassembly table for VXLAN UDP GRO */
17799a2dd95SBruce Richardson struct gro_vxlan_udp4_tbl vxlan_udp_tbl;
17899a2dd95SBruce Richardson struct gro_vxlan_udp4_flow vxlan_udp_flows[RTE_GRO_MAX_BURST_ITEM_NUM];
17999a2dd95SBruce Richardson struct gro_vxlan_udp4_item vxlan_udp_items[RTE_GRO_MAX_BURST_ITEM_NUM]
18099a2dd95SBruce Richardson = {{{0}} };
18199a2dd95SBruce Richardson
18299a2dd95SBruce Richardson struct rte_mbuf *unprocess_pkts[nb_pkts];
18399a2dd95SBruce Richardson uint32_t item_num;
18499a2dd95SBruce Richardson int32_t ret;
18599a2dd95SBruce Richardson uint16_t i, unprocess_num = 0, nb_after_gro = nb_pkts;
18699a2dd95SBruce Richardson uint8_t do_tcp4_gro = 0, do_vxlan_tcp_gro = 0, do_udp4_gro = 0,
187*74080d7dSKumara Parameshwaran do_vxlan_udp_gro = 0, do_tcp6_gro = 0;
18899a2dd95SBruce Richardson
18999a2dd95SBruce Richardson if (unlikely((param->gro_types & (RTE_GRO_IPV4_VXLAN_TCP_IPV4 |
190*74080d7dSKumara Parameshwaran RTE_GRO_TCP_IPV4 | RTE_GRO_TCP_IPV6 |
19199a2dd95SBruce Richardson RTE_GRO_IPV4_VXLAN_UDP_IPV4 |
19299a2dd95SBruce Richardson RTE_GRO_UDP_IPV4)) == 0))
19399a2dd95SBruce Richardson return nb_pkts;
19499a2dd95SBruce Richardson
19599a2dd95SBruce Richardson /* Get the maximum number of packets */
19699a2dd95SBruce Richardson item_num = RTE_MIN(nb_pkts, (param->max_flow_num *
19799a2dd95SBruce Richardson param->max_item_per_flow));
19899a2dd95SBruce Richardson item_num = RTE_MIN(item_num, RTE_GRO_MAX_BURST_ITEM_NUM);
19999a2dd95SBruce Richardson
20099a2dd95SBruce Richardson if (param->gro_types & RTE_GRO_IPV4_VXLAN_TCP_IPV4) {
20199a2dd95SBruce Richardson for (i = 0; i < item_num; i++)
20299a2dd95SBruce Richardson vxlan_tcp_flows[i].start_index = INVALID_ARRAY_INDEX;
20399a2dd95SBruce Richardson
20499a2dd95SBruce Richardson vxlan_tcp_tbl.flows = vxlan_tcp_flows;
20599a2dd95SBruce Richardson vxlan_tcp_tbl.items = vxlan_tcp_items;
20699a2dd95SBruce Richardson vxlan_tcp_tbl.flow_num = 0;
20799a2dd95SBruce Richardson vxlan_tcp_tbl.item_num = 0;
20899a2dd95SBruce Richardson vxlan_tcp_tbl.max_flow_num = item_num;
20999a2dd95SBruce Richardson vxlan_tcp_tbl.max_item_num = item_num;
21099a2dd95SBruce Richardson do_vxlan_tcp_gro = 1;
21199a2dd95SBruce Richardson }
21299a2dd95SBruce Richardson
21399a2dd95SBruce Richardson if (param->gro_types & RTE_GRO_IPV4_VXLAN_UDP_IPV4) {
21499a2dd95SBruce Richardson for (i = 0; i < item_num; i++)
21599a2dd95SBruce Richardson vxlan_udp_flows[i].start_index = INVALID_ARRAY_INDEX;
21699a2dd95SBruce Richardson
21799a2dd95SBruce Richardson vxlan_udp_tbl.flows = vxlan_udp_flows;
21899a2dd95SBruce Richardson vxlan_udp_tbl.items = vxlan_udp_items;
21999a2dd95SBruce Richardson vxlan_udp_tbl.flow_num = 0;
22099a2dd95SBruce Richardson vxlan_udp_tbl.item_num = 0;
22199a2dd95SBruce Richardson vxlan_udp_tbl.max_flow_num = item_num;
22299a2dd95SBruce Richardson vxlan_udp_tbl.max_item_num = item_num;
22399a2dd95SBruce Richardson do_vxlan_udp_gro = 1;
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson
22699a2dd95SBruce Richardson if (param->gro_types & RTE_GRO_TCP_IPV4) {
22799a2dd95SBruce Richardson for (i = 0; i < item_num; i++)
22899a2dd95SBruce Richardson tcp_flows[i].start_index = INVALID_ARRAY_INDEX;
22999a2dd95SBruce Richardson
23099a2dd95SBruce Richardson tcp_tbl.flows = tcp_flows;
23199a2dd95SBruce Richardson tcp_tbl.items = tcp_items;
23299a2dd95SBruce Richardson tcp_tbl.flow_num = 0;
23399a2dd95SBruce Richardson tcp_tbl.item_num = 0;
23499a2dd95SBruce Richardson tcp_tbl.max_flow_num = item_num;
23599a2dd95SBruce Richardson tcp_tbl.max_item_num = item_num;
23699a2dd95SBruce Richardson do_tcp4_gro = 1;
23799a2dd95SBruce Richardson }
23899a2dd95SBruce Richardson
23999a2dd95SBruce Richardson if (param->gro_types & RTE_GRO_UDP_IPV4) {
24099a2dd95SBruce Richardson for (i = 0; i < item_num; i++)
24199a2dd95SBruce Richardson udp_flows[i].start_index = INVALID_ARRAY_INDEX;
24299a2dd95SBruce Richardson
24399a2dd95SBruce Richardson udp_tbl.flows = udp_flows;
24499a2dd95SBruce Richardson udp_tbl.items = udp_items;
24599a2dd95SBruce Richardson udp_tbl.flow_num = 0;
24699a2dd95SBruce Richardson udp_tbl.item_num = 0;
24799a2dd95SBruce Richardson udp_tbl.max_flow_num = item_num;
24899a2dd95SBruce Richardson udp_tbl.max_item_num = item_num;
24999a2dd95SBruce Richardson do_udp4_gro = 1;
25099a2dd95SBruce Richardson }
25199a2dd95SBruce Richardson
252*74080d7dSKumara Parameshwaran if (param->gro_types & RTE_GRO_TCP_IPV6) {
253*74080d7dSKumara Parameshwaran for (i = 0; i < item_num; i++)
254*74080d7dSKumara Parameshwaran tcp6_flows[i].start_index = INVALID_ARRAY_INDEX;
255*74080d7dSKumara Parameshwaran
256*74080d7dSKumara Parameshwaran tcp6_tbl.flows = tcp6_flows;
257*74080d7dSKumara Parameshwaran tcp6_tbl.items = tcp6_items;
258*74080d7dSKumara Parameshwaran tcp6_tbl.flow_num = 0;
259*74080d7dSKumara Parameshwaran tcp6_tbl.item_num = 0;
260*74080d7dSKumara Parameshwaran tcp6_tbl.max_flow_num = item_num;
261*74080d7dSKumara Parameshwaran tcp6_tbl.max_item_num = item_num;
262*74080d7dSKumara Parameshwaran do_tcp6_gro = 1;
263*74080d7dSKumara Parameshwaran }
26499a2dd95SBruce Richardson
26599a2dd95SBruce Richardson for (i = 0; i < nb_pkts; i++) {
26699a2dd95SBruce Richardson /*
26799a2dd95SBruce Richardson * The timestamp is ignored, since all packets
26899a2dd95SBruce Richardson * will be flushed from the tables.
26999a2dd95SBruce Richardson */
27099a2dd95SBruce Richardson if (IS_IPV4_VXLAN_TCP4_PKT(pkts[i]->packet_type) &&
27199a2dd95SBruce Richardson do_vxlan_tcp_gro) {
27299a2dd95SBruce Richardson ret = gro_vxlan_tcp4_reassemble(pkts[i],
27399a2dd95SBruce Richardson &vxlan_tcp_tbl, 0);
27499a2dd95SBruce Richardson if (ret > 0)
27599a2dd95SBruce Richardson /* Merge successfully */
27699a2dd95SBruce Richardson nb_after_gro--;
27799a2dd95SBruce Richardson else if (ret < 0)
27899a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
27999a2dd95SBruce Richardson } else if (IS_IPV4_VXLAN_UDP4_PKT(pkts[i]->packet_type) &&
28099a2dd95SBruce Richardson do_vxlan_udp_gro) {
28199a2dd95SBruce Richardson ret = gro_vxlan_udp4_reassemble(pkts[i],
28299a2dd95SBruce Richardson &vxlan_udp_tbl, 0);
28399a2dd95SBruce Richardson if (ret > 0)
28499a2dd95SBruce Richardson /* Merge successfully */
28599a2dd95SBruce Richardson nb_after_gro--;
28699a2dd95SBruce Richardson else if (ret < 0)
28799a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
28899a2dd95SBruce Richardson } else if (IS_IPV4_TCP_PKT(pkts[i]->packet_type) &&
28999a2dd95SBruce Richardson do_tcp4_gro) {
29099a2dd95SBruce Richardson ret = gro_tcp4_reassemble(pkts[i], &tcp_tbl, 0);
29199a2dd95SBruce Richardson if (ret > 0)
29299a2dd95SBruce Richardson /* merge successfully */
29399a2dd95SBruce Richardson nb_after_gro--;
29499a2dd95SBruce Richardson else if (ret < 0)
29599a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
29699a2dd95SBruce Richardson } else if (IS_IPV4_UDP_PKT(pkts[i]->packet_type) &&
29799a2dd95SBruce Richardson do_udp4_gro) {
29899a2dd95SBruce Richardson ret = gro_udp4_reassemble(pkts[i], &udp_tbl, 0);
29999a2dd95SBruce Richardson if (ret > 0)
30099a2dd95SBruce Richardson /* merge successfully */
30199a2dd95SBruce Richardson nb_after_gro--;
30299a2dd95SBruce Richardson else if (ret < 0)
30399a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
304*74080d7dSKumara Parameshwaran } else if (IS_IPV6_TCP_PKT(pkts[i]->packet_type) &&
305*74080d7dSKumara Parameshwaran do_tcp6_gro) {
306*74080d7dSKumara Parameshwaran ret = gro_tcp6_reassemble(pkts[i], &tcp6_tbl, 0);
307*74080d7dSKumara Parameshwaran if (ret > 0)
308*74080d7dSKumara Parameshwaran /* merge successfully */
309*74080d7dSKumara Parameshwaran nb_after_gro--;
310*74080d7dSKumara Parameshwaran else if (ret < 0)
311*74080d7dSKumara Parameshwaran unprocess_pkts[unprocess_num++] = pkts[i];
31299a2dd95SBruce Richardson } else
31399a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
31499a2dd95SBruce Richardson }
31599a2dd95SBruce Richardson
31699a2dd95SBruce Richardson if ((nb_after_gro < nb_pkts)
31799a2dd95SBruce Richardson || (unprocess_num < nb_pkts)) {
31899a2dd95SBruce Richardson i = 0;
319*74080d7dSKumara Parameshwaran /* Copy unprocessed packets */
320*74080d7dSKumara Parameshwaran if (unprocess_num > 0) {
321*74080d7dSKumara Parameshwaran memcpy(&pkts[i], unprocess_pkts,
322*74080d7dSKumara Parameshwaran sizeof(struct rte_mbuf *) *
323*74080d7dSKumara Parameshwaran unprocess_num);
324*74080d7dSKumara Parameshwaran i = unprocess_num;
325*74080d7dSKumara Parameshwaran }
326*74080d7dSKumara Parameshwaran
32799a2dd95SBruce Richardson /* Flush all packets from the tables */
32899a2dd95SBruce Richardson if (do_vxlan_tcp_gro) {
329*74080d7dSKumara Parameshwaran i += gro_vxlan_tcp4_tbl_timeout_flush(&vxlan_tcp_tbl,
33099a2dd95SBruce Richardson 0, pkts, nb_pkts);
33199a2dd95SBruce Richardson }
33299a2dd95SBruce Richardson
33399a2dd95SBruce Richardson if (do_vxlan_udp_gro) {
33499a2dd95SBruce Richardson i += gro_vxlan_udp4_tbl_timeout_flush(&vxlan_udp_tbl,
33599a2dd95SBruce Richardson 0, &pkts[i], nb_pkts - i);
33699a2dd95SBruce Richardson
33799a2dd95SBruce Richardson }
33899a2dd95SBruce Richardson
33999a2dd95SBruce Richardson if (do_tcp4_gro) {
34099a2dd95SBruce Richardson i += gro_tcp4_tbl_timeout_flush(&tcp_tbl, 0,
34199a2dd95SBruce Richardson &pkts[i], nb_pkts - i);
34299a2dd95SBruce Richardson }
34399a2dd95SBruce Richardson
34499a2dd95SBruce Richardson if (do_udp4_gro) {
34599a2dd95SBruce Richardson i += gro_udp4_tbl_timeout_flush(&udp_tbl, 0,
34699a2dd95SBruce Richardson &pkts[i], nb_pkts - i);
34799a2dd95SBruce Richardson }
348*74080d7dSKumara Parameshwaran
349*74080d7dSKumara Parameshwaran if (do_tcp6_gro) {
350*74080d7dSKumara Parameshwaran i += gro_tcp6_tbl_timeout_flush(&tcp6_tbl, 0,
351*74080d7dSKumara Parameshwaran &pkts[i], nb_pkts - i);
35299a2dd95SBruce Richardson }
35399a2dd95SBruce Richardson }
35499a2dd95SBruce Richardson
35599a2dd95SBruce Richardson return nb_after_gro;
35699a2dd95SBruce Richardson }
35799a2dd95SBruce Richardson
35899a2dd95SBruce Richardson uint16_t
rte_gro_reassemble(struct rte_mbuf ** pkts,uint16_t nb_pkts,void * ctx)35999a2dd95SBruce Richardson rte_gro_reassemble(struct rte_mbuf **pkts,
36099a2dd95SBruce Richardson uint16_t nb_pkts,
36199a2dd95SBruce Richardson void *ctx)
36299a2dd95SBruce Richardson {
36399a2dd95SBruce Richardson struct rte_mbuf *unprocess_pkts[nb_pkts];
36499a2dd95SBruce Richardson struct gro_ctx *gro_ctx = ctx;
365*74080d7dSKumara Parameshwaran void *tcp_tbl, *udp_tbl, *vxlan_tcp_tbl, *vxlan_udp_tbl, *tcp6_tbl;
36699a2dd95SBruce Richardson uint64_t current_time;
36799a2dd95SBruce Richardson uint16_t i, unprocess_num = 0;
368*74080d7dSKumara Parameshwaran uint8_t do_tcp4_gro, do_vxlan_tcp_gro, do_udp4_gro, do_vxlan_udp_gro, do_tcp6_gro;
36999a2dd95SBruce Richardson
37099a2dd95SBruce Richardson if (unlikely((gro_ctx->gro_types & (RTE_GRO_IPV4_VXLAN_TCP_IPV4 |
371*74080d7dSKumara Parameshwaran RTE_GRO_TCP_IPV4 | RTE_GRO_TCP_IPV6 |
37299a2dd95SBruce Richardson RTE_GRO_IPV4_VXLAN_UDP_IPV4 |
37399a2dd95SBruce Richardson RTE_GRO_UDP_IPV4)) == 0))
37499a2dd95SBruce Richardson return nb_pkts;
37599a2dd95SBruce Richardson
37699a2dd95SBruce Richardson tcp_tbl = gro_ctx->tbls[RTE_GRO_TCP_IPV4_INDEX];
37799a2dd95SBruce Richardson vxlan_tcp_tbl = gro_ctx->tbls[RTE_GRO_IPV4_VXLAN_TCP_IPV4_INDEX];
37899a2dd95SBruce Richardson udp_tbl = gro_ctx->tbls[RTE_GRO_UDP_IPV4_INDEX];
37999a2dd95SBruce Richardson vxlan_udp_tbl = gro_ctx->tbls[RTE_GRO_IPV4_VXLAN_UDP_IPV4_INDEX];
380*74080d7dSKumara Parameshwaran tcp6_tbl = gro_ctx->tbls[RTE_GRO_TCP_IPV6_INDEX];
38199a2dd95SBruce Richardson
38299a2dd95SBruce Richardson do_tcp4_gro = (gro_ctx->gro_types & RTE_GRO_TCP_IPV4) ==
38399a2dd95SBruce Richardson RTE_GRO_TCP_IPV4;
38499a2dd95SBruce Richardson do_vxlan_tcp_gro = (gro_ctx->gro_types & RTE_GRO_IPV4_VXLAN_TCP_IPV4) ==
38599a2dd95SBruce Richardson RTE_GRO_IPV4_VXLAN_TCP_IPV4;
38699a2dd95SBruce Richardson do_udp4_gro = (gro_ctx->gro_types & RTE_GRO_UDP_IPV4) ==
38799a2dd95SBruce Richardson RTE_GRO_UDP_IPV4;
38899a2dd95SBruce Richardson do_vxlan_udp_gro = (gro_ctx->gro_types & RTE_GRO_IPV4_VXLAN_UDP_IPV4) ==
38999a2dd95SBruce Richardson RTE_GRO_IPV4_VXLAN_UDP_IPV4;
390*74080d7dSKumara Parameshwaran do_tcp6_gro = (gro_ctx->gro_types & RTE_GRO_TCP_IPV6) == RTE_GRO_TCP_IPV6;
39199a2dd95SBruce Richardson
39299a2dd95SBruce Richardson current_time = rte_rdtsc();
39399a2dd95SBruce Richardson
39499a2dd95SBruce Richardson for (i = 0; i < nb_pkts; i++) {
39599a2dd95SBruce Richardson if (IS_IPV4_VXLAN_TCP4_PKT(pkts[i]->packet_type) &&
39699a2dd95SBruce Richardson do_vxlan_tcp_gro) {
39799a2dd95SBruce Richardson if (gro_vxlan_tcp4_reassemble(pkts[i], vxlan_tcp_tbl,
39899a2dd95SBruce Richardson current_time) < 0)
39999a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
40099a2dd95SBruce Richardson } else if (IS_IPV4_VXLAN_UDP4_PKT(pkts[i]->packet_type) &&
40199a2dd95SBruce Richardson do_vxlan_udp_gro) {
40299a2dd95SBruce Richardson if (gro_vxlan_udp4_reassemble(pkts[i], vxlan_udp_tbl,
40399a2dd95SBruce Richardson current_time) < 0)
40499a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
40599a2dd95SBruce Richardson } else if (IS_IPV4_TCP_PKT(pkts[i]->packet_type) &&
40699a2dd95SBruce Richardson do_tcp4_gro) {
40799a2dd95SBruce Richardson if (gro_tcp4_reassemble(pkts[i], tcp_tbl,
40899a2dd95SBruce Richardson current_time) < 0)
40999a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
41099a2dd95SBruce Richardson } else if (IS_IPV4_UDP_PKT(pkts[i]->packet_type) &&
41199a2dd95SBruce Richardson do_udp4_gro) {
41299a2dd95SBruce Richardson if (gro_udp4_reassemble(pkts[i], udp_tbl,
41399a2dd95SBruce Richardson current_time) < 0)
41499a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
415*74080d7dSKumara Parameshwaran } else if (IS_IPV6_TCP_PKT(pkts[i]->packet_type) &&
416*74080d7dSKumara Parameshwaran do_tcp6_gro) {
417*74080d7dSKumara Parameshwaran if (gro_tcp6_reassemble(pkts[i], tcp6_tbl,
418*74080d7dSKumara Parameshwaran current_time) < 0)
419*74080d7dSKumara Parameshwaran unprocess_pkts[unprocess_num++] = pkts[i];
42099a2dd95SBruce Richardson } else
42199a2dd95SBruce Richardson unprocess_pkts[unprocess_num++] = pkts[i];
42299a2dd95SBruce Richardson }
42399a2dd95SBruce Richardson if (unprocess_num > 0) {
42499a2dd95SBruce Richardson memcpy(pkts, unprocess_pkts, sizeof(struct rte_mbuf *) *
42599a2dd95SBruce Richardson unprocess_num);
42699a2dd95SBruce Richardson }
42799a2dd95SBruce Richardson
42899a2dd95SBruce Richardson return unprocess_num;
42999a2dd95SBruce Richardson }
43099a2dd95SBruce Richardson
43199a2dd95SBruce Richardson uint16_t
rte_gro_timeout_flush(void * ctx,uint64_t timeout_cycles,uint64_t gro_types,struct rte_mbuf ** out,uint16_t max_nb_out)43299a2dd95SBruce Richardson rte_gro_timeout_flush(void *ctx,
43399a2dd95SBruce Richardson uint64_t timeout_cycles,
43499a2dd95SBruce Richardson uint64_t gro_types,
43599a2dd95SBruce Richardson struct rte_mbuf **out,
43699a2dd95SBruce Richardson uint16_t max_nb_out)
43799a2dd95SBruce Richardson {
43899a2dd95SBruce Richardson struct gro_ctx *gro_ctx = ctx;
43999a2dd95SBruce Richardson uint64_t flush_timestamp;
44099a2dd95SBruce Richardson uint16_t num = 0;
44199a2dd95SBruce Richardson uint16_t left_nb_out = max_nb_out;
44299a2dd95SBruce Richardson
44399a2dd95SBruce Richardson gro_types = gro_types & gro_ctx->gro_types;
44499a2dd95SBruce Richardson flush_timestamp = rte_rdtsc() - timeout_cycles;
44599a2dd95SBruce Richardson
44699a2dd95SBruce Richardson if (gro_types & RTE_GRO_IPV4_VXLAN_TCP_IPV4) {
44799a2dd95SBruce Richardson num = gro_vxlan_tcp4_tbl_timeout_flush(gro_ctx->tbls[
44899a2dd95SBruce Richardson RTE_GRO_IPV4_VXLAN_TCP_IPV4_INDEX],
44999a2dd95SBruce Richardson flush_timestamp, out, left_nb_out);
45099a2dd95SBruce Richardson left_nb_out = max_nb_out - num;
45199a2dd95SBruce Richardson }
45299a2dd95SBruce Richardson
45399a2dd95SBruce Richardson if ((gro_types & RTE_GRO_IPV4_VXLAN_UDP_IPV4) && left_nb_out > 0) {
45499a2dd95SBruce Richardson num += gro_vxlan_udp4_tbl_timeout_flush(gro_ctx->tbls[
45599a2dd95SBruce Richardson RTE_GRO_IPV4_VXLAN_UDP_IPV4_INDEX],
45699a2dd95SBruce Richardson flush_timestamp, &out[num], left_nb_out);
45799a2dd95SBruce Richardson left_nb_out = max_nb_out - num;
45899a2dd95SBruce Richardson }
45999a2dd95SBruce Richardson
46099a2dd95SBruce Richardson /* If no available space in 'out', stop flushing. */
46199a2dd95SBruce Richardson if ((gro_types & RTE_GRO_TCP_IPV4) && left_nb_out > 0) {
46299a2dd95SBruce Richardson num += gro_tcp4_tbl_timeout_flush(
46399a2dd95SBruce Richardson gro_ctx->tbls[RTE_GRO_TCP_IPV4_INDEX],
46499a2dd95SBruce Richardson flush_timestamp,
46599a2dd95SBruce Richardson &out[num], left_nb_out);
46699a2dd95SBruce Richardson left_nb_out = max_nb_out - num;
46799a2dd95SBruce Richardson }
46899a2dd95SBruce Richardson
46999a2dd95SBruce Richardson /* If no available space in 'out', stop flushing. */
47099a2dd95SBruce Richardson if ((gro_types & RTE_GRO_UDP_IPV4) && left_nb_out > 0) {
47199a2dd95SBruce Richardson num += gro_udp4_tbl_timeout_flush(
47299a2dd95SBruce Richardson gro_ctx->tbls[RTE_GRO_UDP_IPV4_INDEX],
47399a2dd95SBruce Richardson flush_timestamp,
47499a2dd95SBruce Richardson &out[num], left_nb_out);
475*74080d7dSKumara Parameshwaran left_nb_out = max_nb_out - num;
476*74080d7dSKumara Parameshwaran }
477*74080d7dSKumara Parameshwaran
478*74080d7dSKumara Parameshwaran if ((gro_types & RTE_GRO_TCP_IPV6) && left_nb_out > 0) {
479*74080d7dSKumara Parameshwaran num += gro_tcp6_tbl_timeout_flush(
480*74080d7dSKumara Parameshwaran gro_ctx->tbls[RTE_GRO_TCP_IPV6_INDEX],
481*74080d7dSKumara Parameshwaran flush_timestamp,
482*74080d7dSKumara Parameshwaran &out[num], left_nb_out);
483*74080d7dSKumara Parameshwaran
48499a2dd95SBruce Richardson }
48599a2dd95SBruce Richardson
48699a2dd95SBruce Richardson return num;
48799a2dd95SBruce Richardson }
48899a2dd95SBruce Richardson
48999a2dd95SBruce Richardson uint64_t
rte_gro_get_pkt_count(void * ctx)49099a2dd95SBruce Richardson rte_gro_get_pkt_count(void *ctx)
49199a2dd95SBruce Richardson {
49299a2dd95SBruce Richardson struct gro_ctx *gro_ctx = ctx;
49399a2dd95SBruce Richardson gro_tbl_pkt_count_fn pkt_count_fn;
49499a2dd95SBruce Richardson uint64_t gro_types = gro_ctx->gro_types, flag;
49599a2dd95SBruce Richardson uint64_t item_num = 0;
49699a2dd95SBruce Richardson uint8_t i;
49799a2dd95SBruce Richardson
49899a2dd95SBruce Richardson for (i = 0; i < RTE_GRO_TYPE_MAX_NUM && gro_types; i++) {
49999a2dd95SBruce Richardson flag = 1ULL << i;
50099a2dd95SBruce Richardson if ((gro_types & flag) == 0)
50199a2dd95SBruce Richardson continue;
50299a2dd95SBruce Richardson
50399a2dd95SBruce Richardson gro_types ^= flag;
50499a2dd95SBruce Richardson pkt_count_fn = tbl_pkt_count_fn[i];
50599a2dd95SBruce Richardson if (pkt_count_fn)
50699a2dd95SBruce Richardson item_num += pkt_count_fn(gro_ctx->tbls[i]);
50799a2dd95SBruce Richardson }
50899a2dd95SBruce Richardson
50999a2dd95SBruce Richardson return item_num;
51099a2dd95SBruce Richardson }
511