xref: /dpdk/lib/gro/rte_gro.c (revision 74080d7dcf31f02113df7ac1a38c2ee26a6d72b1)
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