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