xref: /dpdk/lib/gro/gro_vxlan_tcp4.c (revision 547f294357690ab8501f120457a82919b1217517)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2018 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <rte_malloc.h>
699a2dd95SBruce Richardson #include <rte_mbuf.h>
799a2dd95SBruce Richardson #include <rte_ethdev.h>
899a2dd95SBruce Richardson #include <rte_udp.h>
999a2dd95SBruce Richardson 
1099a2dd95SBruce Richardson #include "gro_vxlan_tcp4.h"
1199a2dd95SBruce Richardson 
1299a2dd95SBruce Richardson void *
gro_vxlan_tcp4_tbl_create(uint16_t socket_id,uint16_t max_flow_num,uint16_t max_item_per_flow)1399a2dd95SBruce Richardson gro_vxlan_tcp4_tbl_create(uint16_t socket_id,
1499a2dd95SBruce Richardson 		uint16_t max_flow_num,
1599a2dd95SBruce Richardson 		uint16_t max_item_per_flow)
1699a2dd95SBruce Richardson {
1799a2dd95SBruce Richardson 	struct gro_vxlan_tcp4_tbl *tbl;
1899a2dd95SBruce Richardson 	size_t size;
1999a2dd95SBruce Richardson 	uint32_t entries_num, i;
2099a2dd95SBruce Richardson 
2199a2dd95SBruce Richardson 	entries_num = max_flow_num * max_item_per_flow;
2299a2dd95SBruce Richardson 	entries_num = RTE_MIN(entries_num, GRO_VXLAN_TCP4_TBL_MAX_ITEM_NUM);
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson 	if (entries_num == 0)
2599a2dd95SBruce Richardson 		return NULL;
2699a2dd95SBruce Richardson 
2799a2dd95SBruce Richardson 	tbl = rte_zmalloc_socket(__func__,
2899a2dd95SBruce Richardson 			sizeof(struct gro_vxlan_tcp4_tbl),
2999a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE,
3099a2dd95SBruce Richardson 			socket_id);
3199a2dd95SBruce Richardson 	if (tbl == NULL)
3299a2dd95SBruce Richardson 		return NULL;
3399a2dd95SBruce Richardson 
3499a2dd95SBruce Richardson 	size = sizeof(struct gro_vxlan_tcp4_item) * entries_num;
3599a2dd95SBruce Richardson 	tbl->items = rte_zmalloc_socket(__func__,
3699a2dd95SBruce Richardson 			size,
3799a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE,
3899a2dd95SBruce Richardson 			socket_id);
3999a2dd95SBruce Richardson 	if (tbl->items == NULL) {
4099a2dd95SBruce Richardson 		rte_free(tbl);
4199a2dd95SBruce Richardson 		return NULL;
4299a2dd95SBruce Richardson 	}
4399a2dd95SBruce Richardson 	tbl->max_item_num = entries_num;
4499a2dd95SBruce Richardson 
4599a2dd95SBruce Richardson 	size = sizeof(struct gro_vxlan_tcp4_flow) * entries_num;
4699a2dd95SBruce Richardson 	tbl->flows = rte_zmalloc_socket(__func__,
4799a2dd95SBruce Richardson 			size,
4899a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE,
4999a2dd95SBruce Richardson 			socket_id);
5099a2dd95SBruce Richardson 	if (tbl->flows == NULL) {
5199a2dd95SBruce Richardson 		rte_free(tbl->items);
5299a2dd95SBruce Richardson 		rte_free(tbl);
5399a2dd95SBruce Richardson 		return NULL;
5499a2dd95SBruce Richardson 	}
5599a2dd95SBruce Richardson 
5699a2dd95SBruce Richardson 	for (i = 0; i < entries_num; i++)
5799a2dd95SBruce Richardson 		tbl->flows[i].start_index = INVALID_ARRAY_INDEX;
5899a2dd95SBruce Richardson 	tbl->max_flow_num = entries_num;
5999a2dd95SBruce Richardson 
6099a2dd95SBruce Richardson 	return tbl;
6199a2dd95SBruce Richardson }
6299a2dd95SBruce Richardson 
6399a2dd95SBruce Richardson void
gro_vxlan_tcp4_tbl_destroy(void * tbl)6499a2dd95SBruce Richardson gro_vxlan_tcp4_tbl_destroy(void *tbl)
6599a2dd95SBruce Richardson {
6699a2dd95SBruce Richardson 	struct gro_vxlan_tcp4_tbl *vxlan_tbl = tbl;
6799a2dd95SBruce Richardson 
6899a2dd95SBruce Richardson 	if (vxlan_tbl) {
6999a2dd95SBruce Richardson 		rte_free(vxlan_tbl->items);
7099a2dd95SBruce Richardson 		rte_free(vxlan_tbl->flows);
7199a2dd95SBruce Richardson 	}
7299a2dd95SBruce Richardson 	rte_free(vxlan_tbl);
7399a2dd95SBruce Richardson }
7499a2dd95SBruce Richardson 
7599a2dd95SBruce Richardson static inline uint32_t
find_an_empty_item(struct gro_vxlan_tcp4_tbl * tbl)7699a2dd95SBruce Richardson find_an_empty_item(struct gro_vxlan_tcp4_tbl *tbl)
7799a2dd95SBruce Richardson {
7899a2dd95SBruce Richardson 	uint32_t max_item_num = tbl->max_item_num, i;
7999a2dd95SBruce Richardson 
8099a2dd95SBruce Richardson 	for (i = 0; i < max_item_num; i++)
8199a2dd95SBruce Richardson 		if (tbl->items[i].inner_item.firstseg == NULL)
8299a2dd95SBruce Richardson 			return i;
8399a2dd95SBruce Richardson 	return INVALID_ARRAY_INDEX;
8499a2dd95SBruce Richardson }
8599a2dd95SBruce Richardson 
8699a2dd95SBruce Richardson static inline uint32_t
find_an_empty_flow(struct gro_vxlan_tcp4_tbl * tbl)8799a2dd95SBruce Richardson find_an_empty_flow(struct gro_vxlan_tcp4_tbl *tbl)
8899a2dd95SBruce Richardson {
8999a2dd95SBruce Richardson 	uint32_t max_flow_num = tbl->max_flow_num, i;
9099a2dd95SBruce Richardson 
9199a2dd95SBruce Richardson 	for (i = 0; i < max_flow_num; i++)
9299a2dd95SBruce Richardson 		if (tbl->flows[i].start_index == INVALID_ARRAY_INDEX)
9399a2dd95SBruce Richardson 			return i;
9499a2dd95SBruce Richardson 	return INVALID_ARRAY_INDEX;
9599a2dd95SBruce Richardson }
9699a2dd95SBruce Richardson 
9799a2dd95SBruce Richardson static inline uint32_t
insert_new_item(struct gro_vxlan_tcp4_tbl * tbl,struct rte_mbuf * pkt,uint64_t start_time,uint32_t prev_idx,uint32_t sent_seq,uint16_t outer_ip_id,uint16_t ip_id,uint8_t outer_is_atomic,uint8_t is_atomic)9899a2dd95SBruce Richardson insert_new_item(struct gro_vxlan_tcp4_tbl *tbl,
9999a2dd95SBruce Richardson 		struct rte_mbuf *pkt,
10099a2dd95SBruce Richardson 		uint64_t start_time,
10199a2dd95SBruce Richardson 		uint32_t prev_idx,
10299a2dd95SBruce Richardson 		uint32_t sent_seq,
10399a2dd95SBruce Richardson 		uint16_t outer_ip_id,
10499a2dd95SBruce Richardson 		uint16_t ip_id,
10599a2dd95SBruce Richardson 		uint8_t outer_is_atomic,
10699a2dd95SBruce Richardson 		uint8_t is_atomic)
10799a2dd95SBruce Richardson {
10899a2dd95SBruce Richardson 	uint32_t item_idx;
10999a2dd95SBruce Richardson 
11099a2dd95SBruce Richardson 	item_idx = find_an_empty_item(tbl);
11199a2dd95SBruce Richardson 	if (unlikely(item_idx == INVALID_ARRAY_INDEX))
11299a2dd95SBruce Richardson 		return INVALID_ARRAY_INDEX;
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.firstseg = pkt;
11599a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.lastseg = rte_pktmbuf_lastseg(pkt);
11699a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.start_time = start_time;
11799a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.next_pkt_idx = INVALID_ARRAY_INDEX;
11899a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.sent_seq = sent_seq;
1195c55e819SKumara Parameshwaran 	tbl->items[item_idx].inner_item.l3.ip_id = ip_id;
12099a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.nb_merged = 1;
12199a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.is_atomic = is_atomic;
12299a2dd95SBruce Richardson 	tbl->items[item_idx].outer_ip_id = outer_ip_id;
12399a2dd95SBruce Richardson 	tbl->items[item_idx].outer_is_atomic = outer_is_atomic;
12499a2dd95SBruce Richardson 	tbl->item_num++;
12599a2dd95SBruce Richardson 
12699a2dd95SBruce Richardson 	/* If the previous packet exists, chain the new one with it. */
12799a2dd95SBruce Richardson 	if (prev_idx != INVALID_ARRAY_INDEX) {
12899a2dd95SBruce Richardson 		tbl->items[item_idx].inner_item.next_pkt_idx =
12999a2dd95SBruce Richardson 			tbl->items[prev_idx].inner_item.next_pkt_idx;
13099a2dd95SBruce Richardson 		tbl->items[prev_idx].inner_item.next_pkt_idx = item_idx;
13199a2dd95SBruce Richardson 	}
13299a2dd95SBruce Richardson 
13399a2dd95SBruce Richardson 	return item_idx;
13499a2dd95SBruce Richardson }
13599a2dd95SBruce Richardson 
13699a2dd95SBruce Richardson static inline uint32_t
delete_item(struct gro_vxlan_tcp4_tbl * tbl,uint32_t item_idx,uint32_t prev_item_idx)13799a2dd95SBruce Richardson delete_item(struct gro_vxlan_tcp4_tbl *tbl,
13899a2dd95SBruce Richardson 		uint32_t item_idx,
13999a2dd95SBruce Richardson 		uint32_t prev_item_idx)
14099a2dd95SBruce Richardson {
14199a2dd95SBruce Richardson 	uint32_t next_idx = tbl->items[item_idx].inner_item.next_pkt_idx;
14299a2dd95SBruce Richardson 
14399a2dd95SBruce Richardson 	/* NULL indicates an empty item. */
14499a2dd95SBruce Richardson 	tbl->items[item_idx].inner_item.firstseg = NULL;
14599a2dd95SBruce Richardson 	tbl->item_num--;
14699a2dd95SBruce Richardson 	if (prev_item_idx != INVALID_ARRAY_INDEX)
14799a2dd95SBruce Richardson 		tbl->items[prev_item_idx].inner_item.next_pkt_idx = next_idx;
14899a2dd95SBruce Richardson 
14999a2dd95SBruce Richardson 	return next_idx;
15099a2dd95SBruce Richardson }
15199a2dd95SBruce Richardson 
15299a2dd95SBruce Richardson static inline uint32_t
insert_new_flow(struct gro_vxlan_tcp4_tbl * tbl,struct vxlan_tcp4_flow_key * src,uint32_t item_idx)15399a2dd95SBruce Richardson insert_new_flow(struct gro_vxlan_tcp4_tbl *tbl,
15499a2dd95SBruce Richardson 		struct vxlan_tcp4_flow_key *src,
15599a2dd95SBruce Richardson 		uint32_t item_idx)
15699a2dd95SBruce Richardson {
15799a2dd95SBruce Richardson 	struct vxlan_tcp4_flow_key *dst;
15899a2dd95SBruce Richardson 	uint32_t flow_idx;
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson 	flow_idx = find_an_empty_flow(tbl);
16199a2dd95SBruce Richardson 	if (unlikely(flow_idx == INVALID_ARRAY_INDEX))
16299a2dd95SBruce Richardson 		return INVALID_ARRAY_INDEX;
16399a2dd95SBruce Richardson 
16499a2dd95SBruce Richardson 	dst = &(tbl->flows[flow_idx].key);
16599a2dd95SBruce Richardson 
1665c55e819SKumara Parameshwaran 	ASSIGN_COMMON_TCP_KEY((&(src->inner_key.cmn_key)), (&(dst->inner_key.cmn_key)));
16799a2dd95SBruce Richardson 	dst->inner_key.ip_src_addr = src->inner_key.ip_src_addr;
16899a2dd95SBruce Richardson 	dst->inner_key.ip_dst_addr = src->inner_key.ip_dst_addr;
16999a2dd95SBruce Richardson 
17099a2dd95SBruce Richardson 	dst->vxlan_hdr.vx_flags = src->vxlan_hdr.vx_flags;
17199a2dd95SBruce Richardson 	dst->vxlan_hdr.vx_vni = src->vxlan_hdr.vx_vni;
17299a2dd95SBruce Richardson 	rte_ether_addr_copy(&(src->outer_eth_saddr), &(dst->outer_eth_saddr));
17399a2dd95SBruce Richardson 	rte_ether_addr_copy(&(src->outer_eth_daddr), &(dst->outer_eth_daddr));
17499a2dd95SBruce Richardson 	dst->outer_ip_src_addr = src->outer_ip_src_addr;
17599a2dd95SBruce Richardson 	dst->outer_ip_dst_addr = src->outer_ip_dst_addr;
17699a2dd95SBruce Richardson 	dst->outer_src_port = src->outer_src_port;
17799a2dd95SBruce Richardson 	dst->outer_dst_port = src->outer_dst_port;
17899a2dd95SBruce Richardson 
17999a2dd95SBruce Richardson 	tbl->flows[flow_idx].start_index = item_idx;
18099a2dd95SBruce Richardson 	tbl->flow_num++;
18199a2dd95SBruce Richardson 
18299a2dd95SBruce Richardson 	return flow_idx;
18399a2dd95SBruce Richardson }
18499a2dd95SBruce Richardson 
18599a2dd95SBruce Richardson static inline int
is_same_vxlan_tcp4_flow(struct vxlan_tcp4_flow_key k1,struct vxlan_tcp4_flow_key k2)18699a2dd95SBruce Richardson is_same_vxlan_tcp4_flow(struct vxlan_tcp4_flow_key k1,
18799a2dd95SBruce Richardson 		struct vxlan_tcp4_flow_key k2)
18899a2dd95SBruce Richardson {
18999a2dd95SBruce Richardson 	return (rte_is_same_ether_addr(&k1.outer_eth_saddr,
19099a2dd95SBruce Richardson 					&k2.outer_eth_saddr) &&
19199a2dd95SBruce Richardson 			rte_is_same_ether_addr(&k1.outer_eth_daddr,
19299a2dd95SBruce Richardson 				&k2.outer_eth_daddr) &&
19399a2dd95SBruce Richardson 			(k1.outer_ip_src_addr == k2.outer_ip_src_addr) &&
19499a2dd95SBruce Richardson 			(k1.outer_ip_dst_addr == k2.outer_ip_dst_addr) &&
19599a2dd95SBruce Richardson 			(k1.outer_src_port == k2.outer_src_port) &&
19699a2dd95SBruce Richardson 			(k1.outer_dst_port == k2.outer_dst_port) &&
19799a2dd95SBruce Richardson 			(k1.vxlan_hdr.vx_flags == k2.vxlan_hdr.vx_flags) &&
19899a2dd95SBruce Richardson 			(k1.vxlan_hdr.vx_vni == k2.vxlan_hdr.vx_vni) &&
19999a2dd95SBruce Richardson 			is_same_tcp4_flow(k1.inner_key, k2.inner_key));
20099a2dd95SBruce Richardson }
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson static inline int
check_vxlan_seq_option(struct gro_vxlan_tcp4_item * item,struct rte_tcp_hdr * tcp_hdr,uint32_t sent_seq,uint16_t outer_ip_id,uint16_t ip_id,uint16_t tcp_hl,uint16_t tcp_dl,uint8_t outer_is_atomic,uint8_t is_atomic)20399a2dd95SBruce Richardson check_vxlan_seq_option(struct gro_vxlan_tcp4_item *item,
20499a2dd95SBruce Richardson 		struct rte_tcp_hdr *tcp_hdr,
20599a2dd95SBruce Richardson 		uint32_t sent_seq,
20699a2dd95SBruce Richardson 		uint16_t outer_ip_id,
20799a2dd95SBruce Richardson 		uint16_t ip_id,
20899a2dd95SBruce Richardson 		uint16_t tcp_hl,
20999a2dd95SBruce Richardson 		uint16_t tcp_dl,
21099a2dd95SBruce Richardson 		uint8_t outer_is_atomic,
21199a2dd95SBruce Richardson 		uint8_t is_atomic)
21299a2dd95SBruce Richardson {
21399a2dd95SBruce Richardson 	struct rte_mbuf *pkt = item->inner_item.firstseg;
21499a2dd95SBruce Richardson 	int cmp;
21599a2dd95SBruce Richardson 	uint16_t l2_offset;
21699a2dd95SBruce Richardson 
21799a2dd95SBruce Richardson 	/* Don't merge packets whose outer DF bits are different. */
21899a2dd95SBruce Richardson 	if (unlikely(item->outer_is_atomic ^ outer_is_atomic))
21999a2dd95SBruce Richardson 		return 0;
22099a2dd95SBruce Richardson 
22199a2dd95SBruce Richardson 	l2_offset = pkt->outer_l2_len + pkt->outer_l3_len;
22299a2dd95SBruce Richardson 	cmp = check_seq_option(&item->inner_item, tcp_hdr, sent_seq, ip_id,
22399a2dd95SBruce Richardson 			tcp_hl, tcp_dl, l2_offset, is_atomic);
22499a2dd95SBruce Richardson 	if ((cmp > 0) && (outer_is_atomic ||
22599a2dd95SBruce Richardson 				(outer_ip_id == item->outer_ip_id + 1)))
22699a2dd95SBruce Richardson 		/* Append the new packet. */
22799a2dd95SBruce Richardson 		return 1;
22899a2dd95SBruce Richardson 	else if ((cmp < 0) && (outer_is_atomic ||
22999a2dd95SBruce Richardson 				(outer_ip_id + item->inner_item.nb_merged ==
23099a2dd95SBruce Richardson 				 item->outer_ip_id)))
23199a2dd95SBruce Richardson 		/* Prepend the new packet. */
23299a2dd95SBruce Richardson 		return -1;
23399a2dd95SBruce Richardson 
23499a2dd95SBruce Richardson 	return 0;
23599a2dd95SBruce Richardson }
23699a2dd95SBruce Richardson 
23799a2dd95SBruce Richardson static inline int
merge_two_vxlan_tcp4_packets(struct gro_vxlan_tcp4_item * item,struct rte_mbuf * pkt,int cmp,uint32_t sent_seq,uint8_t tcp_flags,uint16_t outer_ip_id,uint16_t ip_id)23899a2dd95SBruce Richardson merge_two_vxlan_tcp4_packets(struct gro_vxlan_tcp4_item *item,
23999a2dd95SBruce Richardson 		struct rte_mbuf *pkt,
24099a2dd95SBruce Richardson 		int cmp,
24199a2dd95SBruce Richardson 		uint32_t sent_seq,
242*547f2943SKumara Parameshwaran 		uint8_t tcp_flags,
24399a2dd95SBruce Richardson 		uint16_t outer_ip_id,
24499a2dd95SBruce Richardson 		uint16_t ip_id)
24599a2dd95SBruce Richardson {
246*547f2943SKumara Parameshwaran 	if (merge_two_tcp_packets(&item->inner_item, pkt, cmp, sent_seq, tcp_flags,
24799a2dd95SBruce Richardson 				ip_id, pkt->outer_l2_len +
24899a2dd95SBruce Richardson 				pkt->outer_l3_len)) {
24999a2dd95SBruce Richardson 		/* Update the outer IPv4 ID to the large value. */
25099a2dd95SBruce Richardson 		item->outer_ip_id = cmp > 0 ? outer_ip_id : item->outer_ip_id;
25199a2dd95SBruce Richardson 		return 1;
25299a2dd95SBruce Richardson 	}
25399a2dd95SBruce Richardson 
25499a2dd95SBruce Richardson 	return 0;
25599a2dd95SBruce Richardson }
25699a2dd95SBruce Richardson 
25799a2dd95SBruce Richardson static inline void
update_vxlan_header(struct gro_vxlan_tcp4_item * item)25899a2dd95SBruce Richardson update_vxlan_header(struct gro_vxlan_tcp4_item *item)
25999a2dd95SBruce Richardson {
26099a2dd95SBruce Richardson 	struct rte_ipv4_hdr *ipv4_hdr;
26199a2dd95SBruce Richardson 	struct rte_udp_hdr *udp_hdr;
26299a2dd95SBruce Richardson 	struct rte_mbuf *pkt = item->inner_item.firstseg;
26399a2dd95SBruce Richardson 	uint16_t len;
26499a2dd95SBruce Richardson 
26599a2dd95SBruce Richardson 	/* Update the outer IPv4 header. */
26699a2dd95SBruce Richardson 	len = pkt->pkt_len - pkt->outer_l2_len;
26763a98ffeSStephen Hemminger 	ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_ipv4_hdr *,
26899a2dd95SBruce Richardson 					   pkt->outer_l2_len);
26999a2dd95SBruce Richardson 	ipv4_hdr->total_length = rte_cpu_to_be_16(len);
27099a2dd95SBruce Richardson 
27199a2dd95SBruce Richardson 	/* Update the outer UDP header. */
27299a2dd95SBruce Richardson 	len -= pkt->outer_l3_len;
27399a2dd95SBruce Richardson 	udp_hdr = (struct rte_udp_hdr *)((char *)ipv4_hdr + pkt->outer_l3_len);
27499a2dd95SBruce Richardson 	udp_hdr->dgram_len = rte_cpu_to_be_16(len);
27599a2dd95SBruce Richardson 
27699a2dd95SBruce Richardson 	/* Update the inner IPv4 header. */
27799a2dd95SBruce Richardson 	len -= pkt->l2_len;
27899a2dd95SBruce Richardson 	ipv4_hdr = (struct rte_ipv4_hdr *)((char *)udp_hdr + pkt->l2_len);
27999a2dd95SBruce Richardson 	ipv4_hdr->total_length = rte_cpu_to_be_16(len);
28099a2dd95SBruce Richardson }
28199a2dd95SBruce Richardson 
28299a2dd95SBruce Richardson int32_t
gro_vxlan_tcp4_reassemble(struct rte_mbuf * pkt,struct gro_vxlan_tcp4_tbl * tbl,uint64_t start_time)28399a2dd95SBruce Richardson gro_vxlan_tcp4_reassemble(struct rte_mbuf *pkt,
28499a2dd95SBruce Richardson 		struct gro_vxlan_tcp4_tbl *tbl,
28599a2dd95SBruce Richardson 		uint64_t start_time)
28699a2dd95SBruce Richardson {
28799a2dd95SBruce Richardson 	struct rte_ether_hdr *outer_eth_hdr, *eth_hdr;
28899a2dd95SBruce Richardson 	struct rte_ipv4_hdr *outer_ipv4_hdr, *ipv4_hdr;
28999a2dd95SBruce Richardson 	struct rte_tcp_hdr *tcp_hdr;
29099a2dd95SBruce Richardson 	struct rte_udp_hdr *udp_hdr;
29199a2dd95SBruce Richardson 	struct rte_vxlan_hdr *vxlan_hdr;
29299a2dd95SBruce Richardson 	uint32_t sent_seq;
29399a2dd95SBruce Richardson 	int32_t tcp_dl;
29499a2dd95SBruce Richardson 	uint16_t frag_off, outer_ip_id, ip_id;
29599a2dd95SBruce Richardson 	uint8_t outer_is_atomic, is_atomic;
29699a2dd95SBruce Richardson 
29799a2dd95SBruce Richardson 	struct vxlan_tcp4_flow_key key;
29899a2dd95SBruce Richardson 	uint32_t cur_idx, prev_idx, item_idx;
29999a2dd95SBruce Richardson 	uint32_t i, max_flow_num, remaining_flow_num;
30099a2dd95SBruce Richardson 	int cmp;
30199a2dd95SBruce Richardson 	uint16_t hdr_len;
30299a2dd95SBruce Richardson 	uint8_t find;
30399a2dd95SBruce Richardson 
30499a2dd95SBruce Richardson 	/*
30599a2dd95SBruce Richardson 	 * Don't process the packet whose TCP header length is greater
30699a2dd95SBruce Richardson 	 * than 60 bytes or less than 20 bytes.
30799a2dd95SBruce Richardson 	 */
30899a2dd95SBruce Richardson 	if (unlikely(INVALID_TCP_HDRLEN(pkt->l4_len)))
30999a2dd95SBruce Richardson 		return -1;
31099a2dd95SBruce Richardson 
31199a2dd95SBruce Richardson 	outer_eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
31299a2dd95SBruce Richardson 	outer_ipv4_hdr = (struct rte_ipv4_hdr *)((char *)outer_eth_hdr +
31399a2dd95SBruce Richardson 			pkt->outer_l2_len);
31499a2dd95SBruce Richardson 	udp_hdr = (struct rte_udp_hdr *)((char *)outer_ipv4_hdr +
31599a2dd95SBruce Richardson 			pkt->outer_l3_len);
31699a2dd95SBruce Richardson 	vxlan_hdr = (struct rte_vxlan_hdr *)((char *)udp_hdr +
31799a2dd95SBruce Richardson 			sizeof(struct rte_udp_hdr));
31899a2dd95SBruce Richardson 	eth_hdr = (struct rte_ether_hdr *)((char *)vxlan_hdr +
31999a2dd95SBruce Richardson 			sizeof(struct rte_vxlan_hdr));
32099a2dd95SBruce Richardson 	ipv4_hdr = (struct rte_ipv4_hdr *)((char *)udp_hdr + pkt->l2_len);
32199a2dd95SBruce Richardson 	tcp_hdr = (struct rte_tcp_hdr *)((char *)ipv4_hdr + pkt->l3_len);
32299a2dd95SBruce Richardson 
32399a2dd95SBruce Richardson 	/*
32499a2dd95SBruce Richardson 	 * Don't process the packet which has FIN, SYN, RST, PSH, URG,
32599a2dd95SBruce Richardson 	 * ECE or CWR set.
32699a2dd95SBruce Richardson 	 */
32799a2dd95SBruce Richardson 	if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG)
32899a2dd95SBruce Richardson 		return -1;
32999a2dd95SBruce Richardson 
33099a2dd95SBruce Richardson 	hdr_len = pkt->outer_l2_len + pkt->outer_l3_len + pkt->l2_len +
33199a2dd95SBruce Richardson 		pkt->l3_len + pkt->l4_len;
33299a2dd95SBruce Richardson 	/*
33399a2dd95SBruce Richardson 	 * Don't process the packet whose payload length is less than or
33499a2dd95SBruce Richardson 	 * equal to 0.
33599a2dd95SBruce Richardson 	 */
33699a2dd95SBruce Richardson 	tcp_dl = pkt->pkt_len - hdr_len;
33799a2dd95SBruce Richardson 	if (tcp_dl <= 0)
33899a2dd95SBruce Richardson 		return -1;
33999a2dd95SBruce Richardson 
34099a2dd95SBruce Richardson 	/*
34199a2dd95SBruce Richardson 	 * Save IPv4 ID for the packet whose DF bit is 0. For the packet
34299a2dd95SBruce Richardson 	 * whose DF bit is 1, IPv4 ID is ignored.
34399a2dd95SBruce Richardson 	 */
34499a2dd95SBruce Richardson 	frag_off = rte_be_to_cpu_16(outer_ipv4_hdr->fragment_offset);
34599a2dd95SBruce Richardson 	outer_is_atomic =
34699a2dd95SBruce Richardson 		(frag_off & RTE_IPV4_HDR_DF_FLAG) == RTE_IPV4_HDR_DF_FLAG;
34799a2dd95SBruce Richardson 	outer_ip_id = outer_is_atomic ? 0 :
34899a2dd95SBruce Richardson 		rte_be_to_cpu_16(outer_ipv4_hdr->packet_id);
34999a2dd95SBruce Richardson 	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
35099a2dd95SBruce Richardson 	is_atomic = (frag_off & RTE_IPV4_HDR_DF_FLAG) == RTE_IPV4_HDR_DF_FLAG;
35199a2dd95SBruce Richardson 	ip_id = is_atomic ? 0 : rte_be_to_cpu_16(ipv4_hdr->packet_id);
35299a2dd95SBruce Richardson 
35399a2dd95SBruce Richardson 	sent_seq = rte_be_to_cpu_32(tcp_hdr->sent_seq);
35499a2dd95SBruce Richardson 
3555c55e819SKumara Parameshwaran 	rte_ether_addr_copy(&(eth_hdr->src_addr), &(key.inner_key.cmn_key.eth_saddr));
3565c55e819SKumara Parameshwaran 	rte_ether_addr_copy(&(eth_hdr->dst_addr), &(key.inner_key.cmn_key.eth_daddr));
35799a2dd95SBruce Richardson 	key.inner_key.ip_src_addr = ipv4_hdr->src_addr;
35899a2dd95SBruce Richardson 	key.inner_key.ip_dst_addr = ipv4_hdr->dst_addr;
3595c55e819SKumara Parameshwaran 	key.inner_key.cmn_key.recv_ack = tcp_hdr->recv_ack;
3605c55e819SKumara Parameshwaran 	key.inner_key.cmn_key.src_port = tcp_hdr->src_port;
3615c55e819SKumara Parameshwaran 	key.inner_key.cmn_key.dst_port = tcp_hdr->dst_port;
36299a2dd95SBruce Richardson 
36399a2dd95SBruce Richardson 	key.vxlan_hdr.vx_flags = vxlan_hdr->vx_flags;
36499a2dd95SBruce Richardson 	key.vxlan_hdr.vx_vni = vxlan_hdr->vx_vni;
36504d43857SDmitry Kozlyuk 	rte_ether_addr_copy(&(outer_eth_hdr->src_addr), &(key.outer_eth_saddr));
36604d43857SDmitry Kozlyuk 	rte_ether_addr_copy(&(outer_eth_hdr->dst_addr), &(key.outer_eth_daddr));
36799a2dd95SBruce Richardson 	key.outer_ip_src_addr = outer_ipv4_hdr->src_addr;
36899a2dd95SBruce Richardson 	key.outer_ip_dst_addr = outer_ipv4_hdr->dst_addr;
36999a2dd95SBruce Richardson 	key.outer_src_port = udp_hdr->src_port;
37099a2dd95SBruce Richardson 	key.outer_dst_port = udp_hdr->dst_port;
37199a2dd95SBruce Richardson 
37299a2dd95SBruce Richardson 	/* Search for a matched flow. */
37399a2dd95SBruce Richardson 	max_flow_num = tbl->max_flow_num;
37499a2dd95SBruce Richardson 	remaining_flow_num = tbl->flow_num;
37599a2dd95SBruce Richardson 	find = 0;
37699a2dd95SBruce Richardson 	for (i = 0; i < max_flow_num && remaining_flow_num; i++) {
37799a2dd95SBruce Richardson 		if (tbl->flows[i].start_index != INVALID_ARRAY_INDEX) {
37899a2dd95SBruce Richardson 			if (is_same_vxlan_tcp4_flow(tbl->flows[i].key, key)) {
37999a2dd95SBruce Richardson 				find = 1;
38099a2dd95SBruce Richardson 				break;
38199a2dd95SBruce Richardson 			}
38299a2dd95SBruce Richardson 			remaining_flow_num--;
38399a2dd95SBruce Richardson 		}
38499a2dd95SBruce Richardson 	}
38599a2dd95SBruce Richardson 
38699a2dd95SBruce Richardson 	/*
38799a2dd95SBruce Richardson 	 * Can't find a matched flow. Insert a new flow and store the
38899a2dd95SBruce Richardson 	 * packet into the flow.
38999a2dd95SBruce Richardson 	 */
39099a2dd95SBruce Richardson 	if (find == 0) {
39199a2dd95SBruce Richardson 		item_idx = insert_new_item(tbl, pkt, start_time,
39299a2dd95SBruce Richardson 				INVALID_ARRAY_INDEX, sent_seq, outer_ip_id,
39399a2dd95SBruce Richardson 				ip_id, outer_is_atomic, is_atomic);
39499a2dd95SBruce Richardson 		if (item_idx == INVALID_ARRAY_INDEX)
39599a2dd95SBruce Richardson 			return -1;
39699a2dd95SBruce Richardson 		if (insert_new_flow(tbl, &key, item_idx) ==
39799a2dd95SBruce Richardson 				INVALID_ARRAY_INDEX) {
39899a2dd95SBruce Richardson 			/*
39999a2dd95SBruce Richardson 			 * Fail to insert a new flow, so
40099a2dd95SBruce Richardson 			 * delete the inserted packet.
40199a2dd95SBruce Richardson 			 */
40299a2dd95SBruce Richardson 			delete_item(tbl, item_idx, INVALID_ARRAY_INDEX);
40399a2dd95SBruce Richardson 			return -1;
40499a2dd95SBruce Richardson 		}
40599a2dd95SBruce Richardson 		return 0;
40699a2dd95SBruce Richardson 	}
40799a2dd95SBruce Richardson 
40899a2dd95SBruce Richardson 	/* Check all packets in the flow and try to find a neighbor. */
40999a2dd95SBruce Richardson 	cur_idx = tbl->flows[i].start_index;
41099a2dd95SBruce Richardson 	prev_idx = cur_idx;
41199a2dd95SBruce Richardson 	do {
41299a2dd95SBruce Richardson 		cmp = check_vxlan_seq_option(&(tbl->items[cur_idx]), tcp_hdr,
41399a2dd95SBruce Richardson 				sent_seq, outer_ip_id, ip_id, pkt->l4_len,
41499a2dd95SBruce Richardson 				tcp_dl, outer_is_atomic, is_atomic);
41599a2dd95SBruce Richardson 		if (cmp) {
41699a2dd95SBruce Richardson 			if (merge_two_vxlan_tcp4_packets(&(tbl->items[cur_idx]),
417*547f2943SKumara Parameshwaran 						pkt, cmp, sent_seq, tcp_hdr->tcp_flags,
41899a2dd95SBruce Richardson 						outer_ip_id, ip_id))
41999a2dd95SBruce Richardson 				return 1;
42099a2dd95SBruce Richardson 			/*
42199a2dd95SBruce Richardson 			 * Can't merge two packets, as the packet
42299a2dd95SBruce Richardson 			 * length will be greater than the max value.
42399a2dd95SBruce Richardson 			 * Insert the packet into the flow.
42499a2dd95SBruce Richardson 			 */
42599a2dd95SBruce Richardson 			if (insert_new_item(tbl, pkt, start_time, prev_idx,
42699a2dd95SBruce Richardson 						sent_seq, outer_ip_id,
42799a2dd95SBruce Richardson 						ip_id, outer_is_atomic,
42899a2dd95SBruce Richardson 						is_atomic) ==
42999a2dd95SBruce Richardson 					INVALID_ARRAY_INDEX)
43099a2dd95SBruce Richardson 				return -1;
43199a2dd95SBruce Richardson 			return 0;
43299a2dd95SBruce Richardson 		}
43399a2dd95SBruce Richardson 		prev_idx = cur_idx;
43499a2dd95SBruce Richardson 		cur_idx = tbl->items[cur_idx].inner_item.next_pkt_idx;
43599a2dd95SBruce Richardson 	} while (cur_idx != INVALID_ARRAY_INDEX);
43699a2dd95SBruce Richardson 
43799a2dd95SBruce Richardson 	/* Can't find neighbor. Insert the packet into the flow. */
43899a2dd95SBruce Richardson 	if (insert_new_item(tbl, pkt, start_time, prev_idx, sent_seq,
43999a2dd95SBruce Richardson 				outer_ip_id, ip_id, outer_is_atomic,
44099a2dd95SBruce Richardson 				is_atomic) == INVALID_ARRAY_INDEX)
44199a2dd95SBruce Richardson 		return -1;
44299a2dd95SBruce Richardson 
44399a2dd95SBruce Richardson 	return 0;
44499a2dd95SBruce Richardson }
44599a2dd95SBruce Richardson 
44699a2dd95SBruce Richardson uint16_t
gro_vxlan_tcp4_tbl_timeout_flush(struct gro_vxlan_tcp4_tbl * tbl,uint64_t flush_timestamp,struct rte_mbuf ** out,uint16_t nb_out)44799a2dd95SBruce Richardson gro_vxlan_tcp4_tbl_timeout_flush(struct gro_vxlan_tcp4_tbl *tbl,
44899a2dd95SBruce Richardson 		uint64_t flush_timestamp,
44999a2dd95SBruce Richardson 		struct rte_mbuf **out,
45099a2dd95SBruce Richardson 		uint16_t nb_out)
45199a2dd95SBruce Richardson {
45299a2dd95SBruce Richardson 	uint16_t k = 0;
45399a2dd95SBruce Richardson 	uint32_t i, j;
45499a2dd95SBruce Richardson 	uint32_t max_flow_num = tbl->max_flow_num;
45599a2dd95SBruce Richardson 
45699a2dd95SBruce Richardson 	for (i = 0; i < max_flow_num; i++) {
45799a2dd95SBruce Richardson 		if (unlikely(tbl->flow_num == 0))
45899a2dd95SBruce Richardson 			return k;
45999a2dd95SBruce Richardson 
46099a2dd95SBruce Richardson 		j = tbl->flows[i].start_index;
46199a2dd95SBruce Richardson 		while (j != INVALID_ARRAY_INDEX) {
46299a2dd95SBruce Richardson 			if (tbl->items[j].inner_item.start_time <=
46399a2dd95SBruce Richardson 					flush_timestamp) {
46499a2dd95SBruce Richardson 				out[k++] = tbl->items[j].inner_item.firstseg;
46599a2dd95SBruce Richardson 				if (tbl->items[j].inner_item.nb_merged > 1)
46699a2dd95SBruce Richardson 					update_vxlan_header(&(tbl->items[j]));
46799a2dd95SBruce Richardson 				/*
46899a2dd95SBruce Richardson 				 * Delete the item and get the next packet
46999a2dd95SBruce Richardson 				 * index.
47099a2dd95SBruce Richardson 				 */
47199a2dd95SBruce Richardson 				j = delete_item(tbl, j, INVALID_ARRAY_INDEX);
47299a2dd95SBruce Richardson 				tbl->flows[i].start_index = j;
47399a2dd95SBruce Richardson 				if (j == INVALID_ARRAY_INDEX)
47499a2dd95SBruce Richardson 					tbl->flow_num--;
47599a2dd95SBruce Richardson 
47699a2dd95SBruce Richardson 				if (unlikely(k == nb_out))
47799a2dd95SBruce Richardson 					return k;
47899a2dd95SBruce Richardson 			} else
47999a2dd95SBruce Richardson 				/*
48099a2dd95SBruce Richardson 				 * The left packets in the flow won't be
48199a2dd95SBruce Richardson 				 * timeout. Go to check other flows.
48299a2dd95SBruce Richardson 				 */
48399a2dd95SBruce Richardson 				break;
48499a2dd95SBruce Richardson 		}
48599a2dd95SBruce Richardson 	}
48699a2dd95SBruce Richardson 	return k;
48799a2dd95SBruce Richardson }
48899a2dd95SBruce Richardson 
48999a2dd95SBruce Richardson uint32_t
gro_vxlan_tcp4_tbl_pkt_count(void * tbl)49099a2dd95SBruce Richardson gro_vxlan_tcp4_tbl_pkt_count(void *tbl)
49199a2dd95SBruce Richardson {
49299a2dd95SBruce Richardson 	struct gro_vxlan_tcp4_tbl *gro_tbl = tbl;
49399a2dd95SBruce Richardson 
49499a2dd95SBruce Richardson 	if (gro_tbl)
49599a2dd95SBruce Richardson 		return gro_tbl->item_num;
49699a2dd95SBruce Richardson 
49799a2dd95SBruce Richardson 	return 0;
49899a2dd95SBruce Richardson }
499