From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 210C042C61; Thu, 8 Jun 2023 18:52:18 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 10F3640A84; Thu, 8 Jun 2023 18:52:18 +0200 (CEST) Received: from mail-yw1-f173.google.com (mail-yw1-f173.google.com [209.85.128.173]) by mails.dpdk.org (Postfix) with ESMTP id 57E5240A4B for ; Thu, 8 Jun 2023 18:52:16 +0200 (CEST) Received: by mail-yw1-f173.google.com with SMTP id 00721157ae682-568f9caff33so7193407b3.2 for ; Thu, 08 Jun 2023 09:52:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1686243135; x=1688835135; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=Bj/OKePaQHu0M5MzQ1k1kWU16raoKZgm+eCN3zzhXvo=; b=SLiD4UuL5EZAh9dcFmMfynpw+qbrcIqvj0J454yIaS0PoJSa8haQSbCXHkVktDRFYR bZihhcgYwOD2gh+AHi5ec+4dZtNDJJJCxFSDwt4/d7Fsj1dmLByMI/4yIBkf/0pz8EEo MqjVg59p/5Y03osYrVW9uXxwyeHshKtgqDnGcpBv9BxPYxEWdMloljawjIYiPrnTpjBv K/q4EAM/5G3U1/8o90VfbkNM0MABov2MSfvJzLzcrogQPzzX6dRvohz+xT0uisdn2th/ HjgsG+Pc1+6yKdSi7jHr+16fYTnwFE1xI8gskmYZ/xmL2OFDMrHhPGpfDIIGKbwCjdN9 JDhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686243135; x=1688835135; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Bj/OKePaQHu0M5MzQ1k1kWU16raoKZgm+eCN3zzhXvo=; b=W1qXzvdyymroHNbSP5gqbBiyj8qbt+AGpbHejnLGdN3KjVK8vEZKdVlR3I5myRRXir FrMB4+4sLXauC6jP3AjIXXSeHTop+teBCGedOFbwflUtC2p0NeTSyL55WiYNuKZuI0Z3 5S/lca+3cSSLUAPMj1OiFdUXcYrh+dqqiiN6aQdCCsRSrvR2z25ytB0srdny6onlt87j I667ta6yn7JMDp2+3Qg9kgY8aRzbObUan5uRzErOdh1LVWyzgiD3s3LdcGmfmujye0pU OLzBHqhkDoiZzCE309M153JTLeYspiK0DcawWXCiOM9G/2yvI1v9lmVAEP6lKVdU6VlB 0ITw== X-Gm-Message-State: AC+VfDxxOYR8TO2y/UXFPYVQrHB4IB5DJYEvrdlZweU55FImuhXL8XqN E04F4mbj1d7ejrTmkcDXzsFroU1/lbd3zJhTftOewt1j X-Google-Smtp-Source: ACHHUZ7CpOI2E64y9W6VCbNqcebruDdGqSSXWMEoicih5FayRno0T2LNiaBrxcnDxwYa+Q15WjaVq5XMVZPnwdGhgP8= X-Received: by 2002:a81:6646:0:b0:565:3571:79fd with SMTP id a67-20020a816646000000b00565357179fdmr199413ywc.47.1686243135491; Thu, 08 Jun 2023 09:52:15 -0700 (PDT) MIME-Version: 1.0 References: <20221020181425.48006-1-kumaraparmesh92@gmail.com> <20230606145802.53671-1-kumaraparamesh92@gmail.com> In-Reply-To: From: kumaraparameshwaran rathinavel Date: Thu, 8 Jun 2023 22:22:04 +0530 Message-ID: Subject: Re: [PATCH v4] gro : ipv6 changes to support GRO for TCP/ipv6 To: "Hu, Jiayu" Cc: "dev@dpdk.org" Content-Type: multipart/alternative; boundary="000000000000189e1005fda1133c" X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org --000000000000189e1005fda1133c Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Jiyau, Thanks for the quick review comments. Will address the review comments. Require clarification in one of the comments. Please find it inline. On Thu, Jun 8, 2023 at 9:35=E2=80=AFAM Hu, Jiayu wrote= : > Hi Kumara, > > Please see replies inline. > > In addition, you need to update the programmer guide in > generic_receive_offload_lib.rst, > and release note release_23_07.rst. > > Thanks, > Jiayu > > > -----Original Message----- > > From: Kumara Parameshwaran > > Sent: Tuesday, June 6, 2023 10:58 PM > > To: Hu, Jiayu > > Cc: dev@dpdk.org; Kumara Parameshwaran > > > > Subject: [PATCH v4] gro : ipv6 changes to support GRO for TCP/ipv6 > > > > The patch adds GRO support for TCP/ipv6 packets. This does not include > the > > support for vxlan, udp ipv6 packets. > > > > Signed-off-by: Kumara Parameshwaran > > > diff --git a/lib/gro/gro_tcp.c b/lib/gro/gro_tcp.c new file mode 100644 > index > > 0000000000..02a7d0f8c5 > > --- /dev/null > > +++ b/lib/gro/gro_tcp.c > > For gro_tcp.c and gro_tcp.h, it's better to add "_internal" in the file > name. > > > @@ -0,0 +1,128 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2017 Intel Corporation > > + */ > > +#include > > +#include > > +#include > > + > > +#include "gro_tcp.h" > > + > > +static inline uint32_t > > +find_an_empty_item(struct gro_tcp_item *items, > > + uint32_t max_item_num) > > +{ > > + uint32_t i; > > + > > + for (i =3D 0; i < max_item_num; i++) > > + if (items[i].firstseg =3D=3D NULL) > > + return i; > > + return INVALID_ARRAY_INDEX; > > +} > > + > > +uint32_t > > +insert_new_tcp_item(struct rte_mbuf *pkt, > > + struct gro_tcp_item *items, > > + uint32_t *item_num, > > + uint32_t max_item_num, > > + uint64_t start_time, > > + uint32_t prev_idx, > > + uint32_t sent_seq, > > + uint16_t ip_id, > > + uint8_t is_atomic) > > This function can be inline. > > > +{ > > + uint32_t item_idx; > > + > > + item_idx =3D find_an_empty_item(items, max_item_num); > > + if (item_idx =3D=3D INVALID_ARRAY_INDEX) > > + return INVALID_ARRAY_INDEX; > > + > > + items[item_idx].firstseg =3D pkt; > > + items[item_idx].lastseg =3D rte_pktmbuf_lastseg(pkt); > > + items[item_idx].start_time =3D start_time; > > + items[item_idx].next_pkt_idx =3D INVALID_ARRAY_INDEX; > > + items[item_idx].sent_seq =3D sent_seq; > > + items[item_idx].ip_id =3D ip_id; > > + items[item_idx].nb_merged =3D 1; > > + items[item_idx].is_atomic =3D is_atomic; > > + (*item_num) +=3D 1; > > + > > + /* if the previous packet exists, chain them together. */ > > + if (prev_idx !=3D INVALID_ARRAY_INDEX) { > > + items[item_idx].next_pkt_idx =3D > > + items[prev_idx].next_pkt_idx; > > + items[prev_idx].next_pkt_idx =3D item_idx; > > + } > > + > > + return item_idx; > > +} > > + > > +uint32_t > > +delete_tcp_item(struct gro_tcp_item *items, uint32_t item_idx, > > + uint32_t *item_num, > > + uint32_t prev_item_idx) > > +{ > > + uint32_t next_idx =3D items[item_idx].next_pkt_idx; > > + > > + /* NULL indicates an empty item */ > > + items[item_idx].firstseg =3D NULL; > > + (*item_num) -=3D 1; > > + if (prev_item_idx !=3D INVALID_ARRAY_INDEX) > > + items[prev_item_idx].next_pkt_idx =3D next_idx; > > + > > + return next_idx; > > +} > > This function can be inline. > > > + > > +int32_t > > +gro_process_tcp_item(struct rte_mbuf *pkt, > > + struct rte_tcp_hdr *tcp_hdr, > > + int32_t tcp_dl, > > + struct gro_tcp_item *items, > > + uint32_t item_idx, > > + uint32_t *item_num, > > + uint32_t max_item_num, > > + uint16_t ip_id, > > + uint8_t is_atomic, > > + uint64_t start_time) > > It is for internal use, so it's better to remove "gro_" from the function > name. > > > +{ > > + uint32_t cur_idx; > > + uint32_t prev_idx; > > + int cmp; > > + uint32_t sent_seq; > > + > > + sent_seq =3D rte_be_to_cpu_32(tcp_hdr->sent_seq); > > + /* > > + * Check all packets in the flow and try to find a neighbor for > > + * the input packet. > > + */ > > + cur_idx =3D item_idx; > > + prev_idx =3D cur_idx; > > + do { > > + cmp =3D check_seq_option(&items[cur_idx], tcp_hdr, > > + sent_seq, ip_id, pkt->l4_len, tcp_dl, 0, > > + is_atomic); > > + if (cmp) { > > + if (merge_two_tcp_packets(&items[cur_idx], > > + pkt, cmp, sent_seq, ip_id= , > 0)) > > + return 1; > > + /* > > + * Fail to merge the two packets, as the packet > > + * length is greater than the max value. Store > > + * the packet into the flow. > > + */ > > + if (insert_new_tcp_item(pkt, items, item_num, > > max_item_num, start_time, cur_idx, > > + sent_seq, ip_id, > is_atomic) =3D=3D > > + INVALID_ARRAY_INDEX) > > + return -1; > > + return 0; > > + } > > + prev_idx =3D cur_idx; > > + cur_idx =3D items[cur_idx].next_pkt_idx; > > + } while (cur_idx !=3D INVALID_ARRAY_INDEX); > > + > > + /* Fail to find a neighbor, so store the packet into the flow. */ > > + if (insert_new_tcp_item(pkt, items, item_num, max_item_num, > > start_time, prev_idx, sent_seq, > > + ip_id, is_atomic) =3D=3D INVALID_ARRAY_IN= DEX) > > + return -1; > > + > > + return 0; > > +} > > diff --git a/lib/gro/gro_tcp.h b/lib/gro/gro_tcp.h new file mode 100644 > index > > 0000000000..4b5b4eda9c > > --- /dev/null > > +++ b/lib/gro/gro_tcp.h > > @@ -0,0 +1,209 @@ > > +#ifndef _GRO_TCP_H_ > > +#define _GRO_TCP_H_ > > + > > +#define INVALID_ARRAY_INDEX 0xffffffffUL > > + > > +#include > > + > > +/* > > + * The max length of a IPv4 packet, which includes the length of the L= 3 > > + * header, the L4 header and the data payload. > > + */ > > +#define MAX_IP_PKT_LENGTH UINT16_MAX > > + > > +/* The maximum TCP header length */ > > +#define MAX_TCP_HLEN 60 > > +#define INVALID_TCP_HDRLEN(len) \ > > + (((len) < sizeof(struct rte_tcp_hdr)) || ((len) > MAX_TCP_HLEN)) > > + > > +struct gro_tcp_flow { > > This structure name is confusing. In the upper layer, tcp4 and tcp6 have > gro_tcp4_flow > and gro_tcp6_flow, which represent a flow. Inside gro_tcp4/6_flow, there > are keys, > represented by struct tcp4/6_flow_key. But inside struct tcp4/6_flow_key, > there is > struct gro_tcp_flow. Need to rename struct gro_tcp_flow, like > common_tcp_flow_key. > > > + struct rte_ether_addr eth_saddr; > > + struct rte_ether_addr eth_daddr; > > + uint32_t recv_ack; > > + uint16_t src_port; > > + uint16_t dst_port; > > +}; > > + > > +#define ASSIGN_TCP_FLOW_KEY(k1, k2) \ > > Ditto. The macro needs rename, like ASSIGN_COMMON_TCP_FLOW_KEY. > > > + do {\ > > + rte_ether_addr_copy(&(k1->eth_saddr), &(k2->eth_saddr)); = \ > > + rte_ether_addr_copy(&(k1->eth_daddr), &(k2->eth_daddr)); > > \ > > + k2->recv_ack =3D k1->recv_ack; \ > > + k2->src_port =3D k1->src_port; \ > > + k2->dst_port =3D k1->dst_port; \ > > + } while (0) > > + > > +struct gro_tcp_item { > > + /* > > + * The first MBUF segment of the packet. If the value > > + * is NULL, it means the item is empty. > > + */ > > + struct rte_mbuf *firstseg; > > + /* The last MBUF segment of the packet */ > > + struct rte_mbuf *lastseg; > > + /* > > + * The time when the first packet is inserted into the table. > > + * This value won't be updated, even if the packet is merged > > + * with other packets. > > + */ > > + uint64_t start_time; > > + /* > > + * next_pkt_idx is used to chain the packets that > > + * are in the same flow but can't be merged together > > + * (e.g. caused by packet reordering). > > + */ > > + uint32_t next_pkt_idx; > > + /* TCP sequence number of the packet */ > > + uint32_t sent_seq; > > + /* IPv4 ID of the packet */ > > + uint16_t ip_id; > > The ip_id field is not used by tcp6. It's better to use an union to > include ip_id for IPv4 and > an useless member for IPv6 with some comments to avoid confusing. > > > + /* the number of merged packets */ > > + uint16_t nb_merged; > > + /* Indicate if IPv4 ID can be ignored */ > > + uint8_t is_atomic; > > +}; > > + > > +uint32_t > > +insert_new_tcp_item(struct rte_mbuf *pkt, > > + struct gro_tcp_item *items, > > + uint32_t *item_num, > > + uint32_t table_size, > > + uint64_t start_time, > > + uint32_t prev_idx, > > + uint32_t sent_seq, > > + uint16_t ip_id, > > + uint8_t is_atomic); > > + > > +uint32_t > > +delete_tcp_item(struct gro_tcp_item *items, > > + uint32_t item_idx, > > + uint32_t *item_num, > > + uint32_t prev_item_idx); > > + > > +int32_t > > +gro_process_tcp_item(struct rte_mbuf *pkt, > > + struct rte_tcp_hdr *tcp_hdr, > > + int32_t tcp_dl, > > + struct gro_tcp_item *items, > > + uint32_t item_idx, > > + uint32_t *item_num, > > + uint32_t table_size, > > + uint16_t ip_id, > > + uint8_t is_atomic, > > + uint64_t start_time); > > + > > +/* > > + * Merge two TCP packets without updating checksums. > > + * If cmp is larger than 0, append the new packet to the > > + * original packet. Otherwise, pre-pend the new packet to > > + * the original packet. > > + */ > > +static inline int > > +merge_two_tcp_packets(struct gro_tcp_item *item, > > + struct rte_mbuf *pkt, > > + int cmp, > > + uint32_t sent_seq, > > + uint16_t ip_id, > > + uint16_t l2_offset) > > +{ > > + struct rte_mbuf *pkt_head, *pkt_tail, *lastseg; > > + uint16_t hdr_len, l2_len; > > + > > + if (cmp > 0) { > > + pkt_head =3D item->firstseg; > > + pkt_tail =3D pkt; > > + } else { > > + pkt_head =3D pkt; > > + pkt_tail =3D item->firstseg; > > + } > > + > > + /* check if the IPv4 packet length is greater than the max value = */ > > + hdr_len =3D l2_offset + pkt_head->l2_len + pkt_head->l3_len + > > + pkt_head->l4_len; > > + l2_len =3D l2_offset > 0 ? pkt_head->outer_l2_len : pkt_head->l2_= len; > > + if (unlikely(pkt_head->pkt_len - l2_len + pkt_tail->pkt_len - > > + hdr_len > MAX_IP_PKT_LENGTH)) > > + return 0; > > + > > + /* remove the packet header for the tail packet */ > > + rte_pktmbuf_adj(pkt_tail, hdr_len); > > + > > + /* chain two packets together */ > > + if (cmp > 0) { > > + item->lastseg->next =3D pkt; > > + item->lastseg =3D rte_pktmbuf_lastseg(pkt); > > + /* update IP ID to the larger value */ > > + item->ip_id =3D ip_id; > > + } else { > > + lastseg =3D rte_pktmbuf_lastseg(pkt); > > + lastseg->next =3D item->firstseg; > > + item->firstseg =3D pkt; > > + /* update sent_seq to the smaller value */ > > + item->sent_seq =3D sent_seq; > > + item->ip_id =3D ip_id; > > + } > > + item->nb_merged++; > > + > > + /* update MBUF metadata for the merged packet */ > > + pkt_head->nb_segs +=3D pkt_tail->nb_segs; > > + pkt_head->pkt_len +=3D pkt_tail->pkt_len; > > + > > + return 1; > > +} > > + > > +/* > > + * Check if two TCP/IPv4 packets are neighbors. > > + */ > > +static inline int > > +check_seq_option(struct gro_tcp_item *item, > > + struct rte_tcp_hdr *tcph, > > + uint32_t sent_seq, > > + uint16_t ip_id, > > + uint16_t tcp_hl, > > + uint16_t tcp_dl, > > + uint16_t l2_offset, > > + uint8_t is_atomic) > > +{ > > + struct rte_mbuf *pkt_orig =3D item->firstseg; > > + char *iph_orig; > > + struct rte_tcp_hdr *tcph_orig; > > + uint16_t len, tcp_hl_orig; > > + > > + iph_orig =3D (char *)(rte_pktmbuf_mtod(pkt_orig, char *) + > > + l2_offset + pkt_orig->l2_len); > > + tcph_orig =3D (struct rte_tcp_hdr *)(iph_orig + pkt_orig->l3_len)= ; > > + tcp_hl_orig =3D pkt_orig->l4_len; > > + > > + /* Check if TCP option fields equal */ > > + len =3D RTE_MAX(tcp_hl, tcp_hl_orig) - sizeof(struct rte_tcp_hdr)= ; > > + if ((tcp_hl !=3D tcp_hl_orig) || ((len > 0) && > > + (memcmp(tcph + 1, tcph_orig + 1, > > + len) !=3D 0))) > > + return 0; > > + > > + /* Don't merge packets whose DF bits are different */ > > + if (unlikely(item->is_atomic ^ is_atomic)) > > + return 0; > > + > > + /* check if the two packets are neighbors */ > > + len =3D pkt_orig->pkt_len - l2_offset - pkt_orig->l2_len - > > + pkt_orig->l3_len - tcp_hl_orig; > > + if ((sent_seq =3D=3D item->sent_seq + len) && (is_atomic || > > + (ip_id =3D=3D item->ip_id + 1))) > > + /* append the new packet */ > > + return 1; > > + else if ((sent_seq + tcp_dl =3D=3D item->sent_seq) && (is_atomic = || > > + (ip_id + item->nb_merged =3D=3D item->ip_= id))) > > + /* pre-pend the new packet */ > > + return -1; > > + > > + return 0; > > +} > > + > > +static inline int > > +is_same_tcp_flow(struct gro_tcp_flow *k1, struct gro_tcp_flow *k2) { > > + return (!memcmp(k1, k2, sizeof(struct gro_tcp_flow))); } > > I think this function needs rename, as the result of this function cannot > identify if they are > same TCP flow. > > > + > > +#endif > > diff --git a/lib/gro/gro_tcp4.c b/lib/gro/gro_tcp4.c index > > 0014096e63..ffc33747c4 100644 > > --- a/lib/gro/gro_tcp4.c > > +++ b/lib/gro/gro_tcp4.c > > @@ -7,6 +7,7 @@ > > #include > > > > #include "gro_tcp4.h" > > +#include "gro_tcp.h" > > > > void * > > gro_tcp4_tbl_create(uint16_t socket_id, @@ -30,7 +31,7 @@ > > gro_tcp4_tbl_create(uint16_t socket_id, > > if (tbl =3D=3D NULL) > > return NULL; > > > > - size =3D sizeof(struct gro_tcp4_item) * entries_num; > > + size =3D sizeof(struct gro_tcp_item) * entries_num; > > tbl->items =3D rte_zmalloc_socket(__func__, > > size, > > RTE_CACHE_LINE_SIZE, > > @@ -71,18 +72,6 @@ gro_tcp4_tbl_destroy(void *tbl) > > rte_free(tcp_tbl); > > } > > > > -static inline uint32_t > > -find_an_empty_item(struct gro_tcp4_tbl *tbl) -{ > > - uint32_t i; > > - uint32_t max_item_num =3D tbl->max_item_num; > > - > > - for (i =3D 0; i < max_item_num; i++) > > - if (tbl->items[i].firstseg =3D=3D NULL) > > - return i; > > - return INVALID_ARRAY_INDEX; > > -} > > - > > static inline uint32_t > > find_an_empty_flow(struct gro_tcp4_tbl *tbl) { @@ -95,56 +84,6 @@ > > find_an_empty_flow(struct gro_tcp4_tbl *tbl) > > return INVALID_ARRAY_INDEX; > > } > > > > -static inline uint32_t > > -insert_new_item(struct gro_tcp4_tbl *tbl, > > - struct rte_mbuf *pkt, > > - uint64_t start_time, > > - uint32_t prev_idx, > > - uint32_t sent_seq, > > - uint16_t ip_id, > > - uint8_t is_atomic) > > -{ > > - uint32_t item_idx; > > - > > - item_idx =3D find_an_empty_item(tbl); > > - if (item_idx =3D=3D INVALID_ARRAY_INDEX) > > - return INVALID_ARRAY_INDEX; > > - > > - tbl->items[item_idx].firstseg =3D pkt; > > - tbl->items[item_idx].lastseg =3D rte_pktmbuf_lastseg(pkt); > > - tbl->items[item_idx].start_time =3D start_time; > > - tbl->items[item_idx].next_pkt_idx =3D INVALID_ARRAY_INDEX; > > - tbl->items[item_idx].sent_seq =3D sent_seq; > > - tbl->items[item_idx].ip_id =3D ip_id; > > - tbl->items[item_idx].nb_merged =3D 1; > > - tbl->items[item_idx].is_atomic =3D is_atomic; > > - tbl->item_num++; > > - > > - /* if the previous packet exists, chain them together. */ > > - if (prev_idx !=3D INVALID_ARRAY_INDEX) { > > - tbl->items[item_idx].next_pkt_idx =3D > > - tbl->items[prev_idx].next_pkt_idx; > > - tbl->items[prev_idx].next_pkt_idx =3D item_idx; > > - } > > - > > - return item_idx; > > -} > > - > > -static inline uint32_t > > -delete_item(struct gro_tcp4_tbl *tbl, uint32_t item_idx, > > - uint32_t prev_item_idx) > > -{ > > - uint32_t next_idx =3D tbl->items[item_idx].next_pkt_idx; > > - > > - /* NULL indicates an empty item */ > > - tbl->items[item_idx].firstseg =3D NULL; > > - tbl->item_num--; > > - if (prev_item_idx !=3D INVALID_ARRAY_INDEX) > > - tbl->items[prev_item_idx].next_pkt_idx =3D next_idx; > > - > > - return next_idx; > > -} > > - > > static inline uint32_t > > insert_new_flow(struct gro_tcp4_tbl *tbl, > > struct tcp4_flow_key *src, > > @@ -159,13 +98,10 @@ insert_new_flow(struct gro_tcp4_tbl *tbl, > > > > dst =3D &(tbl->flows[flow_idx].key); > > > > - rte_ether_addr_copy(&(src->eth_saddr), &(dst->eth_saddr)); > > - rte_ether_addr_copy(&(src->eth_daddr), &(dst->eth_daddr)); > > + ASSIGN_TCP_FLOW_KEY((&src->tcp_flow), (&dst->tcp_flow)); > > + > > dst->ip_src_addr =3D src->ip_src_addr; > > dst->ip_dst_addr =3D src->ip_dst_addr; > > - dst->recv_ack =3D src->recv_ack; > > - dst->src_port =3D src->src_port; > > - dst->dst_port =3D src->dst_port; > > > > tbl->flows[flow_idx].start_index =3D item_idx; > > tbl->flow_num++; > > @@ -173,21 +109,6 @@ insert_new_flow(struct gro_tcp4_tbl *tbl, > > return flow_idx; > > } > > > > -/* > > - * update the packet length for the flushed packet. > > - */ > > -static inline void > > -update_header(struct gro_tcp4_item *item) -{ > > - struct rte_ipv4_hdr *ipv4_hdr; > > - struct rte_mbuf *pkt =3D item->firstseg; > > - > > - ipv4_hdr =3D (struct rte_ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *= ) + > > - pkt->l2_len); > > - ipv4_hdr->total_length =3D rte_cpu_to_be_16(pkt->pkt_len - > > - pkt->l2_len); > > -} > > - > > int32_t > > gro_tcp4_reassemble(struct rte_mbuf *pkt, > > struct gro_tcp4_tbl *tbl, > > @@ -195,16 +116,15 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt, { > > struct rte_ether_hdr *eth_hdr; > > struct rte_ipv4_hdr *ipv4_hdr; > > - struct rte_tcp_hdr *tcp_hdr; > > - uint32_t sent_seq; > > int32_t tcp_dl; > > + struct rte_tcp_hdr *tcp_hdr; > > uint16_t ip_id, hdr_len, frag_off, ip_tlen; > > uint8_t is_atomic; > > + uint32_t sent_seq; > > No need to change tcp_hdr and sent_seq here. > >> The flow matching is done in the function and if the flow is not found >> insert_new_tcp_item is invoked from this function itself. Did you mean t= o >> move that to the process_tcp_item as well? If that is the case we should >> pass the start_idx as INVALID_ARRAY_INDEX and in process_tcp_item check = if >> INVALID_ARRAY_INDEX do a insert_new_tcp_item and return, do not do the >> sequnce number checks etc. >> > > > > struct tcp4_flow_key key; > > - uint32_t cur_idx, prev_idx, item_idx; > > + uint32_t item_idx; > > uint32_t i, max_flow_num, remaining_flow_num; > > - int cmp; > > uint8_t find; > > > > /* > > @@ -216,7 +136,7 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt, > > > > eth_hdr =3D rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); > > ipv4_hdr =3D (struct rte_ipv4_hdr *)((char *)eth_hdr + pkt->l2_le= n); > > - tcp_hdr =3D (struct rte_tcp_hdr *)((char *)ipv4_hdr + pkt->l3_len= ); > > + tcp_hdr =3D rte_pktmbuf_mtod_offset(pkt, struct rte_tcp_hdr *, > > +pkt->l2_len + pkt->l3_len); > > hdr_len =3D pkt->l2_len + pkt->l3_len + pkt->l4_len; > > > > /* > > @@ -230,7 +150,6 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt, > > ip_tlen =3D rte_be_to_cpu_16(ipv4_hdr->total_length); > > if (pkt->pkt_len > (uint32_t)(ip_tlen + pkt->l2_len)) > > rte_pktmbuf_trim(pkt, pkt->pkt_len - ip_tlen - > pkt->l2_len); > > - > > /* > > * Don't process the packet whose payload length is less than or > > * equal to 0. > > @@ -239,6 +158,13 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt, > > if (tcp_dl <=3D 0) > > return -1; > > > > + rte_ether_addr_copy(&(eth_hdr->src_addr), > > &(key.tcp_flow.eth_saddr)); > > + rte_ether_addr_copy(&(eth_hdr->dst_addr), > > &(key.tcp_flow.eth_daddr)); > > + key.ip_src_addr =3D ipv4_hdr->src_addr; > > + key.ip_dst_addr =3D ipv4_hdr->dst_addr; > > + key.tcp_flow.src_port =3D tcp_hdr->src_port; > > + key.tcp_flow.dst_port =3D tcp_hdr->dst_port; > > + key.tcp_flow.recv_ack =3D tcp_hdr->recv_ack; > > /* > > * Save IPv4 ID for the packet whose DF bit is 0. For the packet > > * whose DF bit is 1, IPv4 ID is ignored. > > @@ -246,15 +172,6 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt, > > frag_off =3D rte_be_to_cpu_16(ipv4_hdr->fragment_offset); > > is_atomic =3D (frag_off & RTE_IPV4_HDR_DF_FLAG) =3D=3D > > RTE_IPV4_HDR_DF_FLAG; > > ip_id =3D is_atomic ? 0 : rte_be_to_cpu_16(ipv4_hdr->packet_id); > > - sent_seq =3D rte_be_to_cpu_32(tcp_hdr->sent_seq); > > - > > - rte_ether_addr_copy(&(eth_hdr->src_addr), &(key.eth_saddr)); > > - rte_ether_addr_copy(&(eth_hdr->dst_addr), &(key.eth_daddr)); > > - key.ip_src_addr =3D ipv4_hdr->src_addr; > > - key.ip_dst_addr =3D ipv4_hdr->dst_addr; > > - key.src_port =3D tcp_hdr->src_port; > > - key.dst_port =3D tcp_hdr->dst_port; > > - key.recv_ack =3D tcp_hdr->recv_ack; > > > > /* Search for a matched flow. */ > > max_flow_num =3D tbl->max_flow_num; > > @@ -270,63 +187,44 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt, > > } > > } > > > > - /* > > - * Fail to find a matched flow. Insert a new flow and store the > > - * packet into the flow. > > - */ > > if (find =3D=3D 0) { > > - item_idx =3D insert_new_item(tbl, pkt, start_time, > > - INVALID_ARRAY_INDEX, sent_seq, ip_id, > > - is_atomic); > > + sent_seq =3D rte_be_to_cpu_32(tcp_hdr->sent_seq); > > + item_idx =3D insert_new_tcp_item(pkt, tbl->items, &tbl- > > >item_num, tbl->max_item_num, start_time, > > + INVALID_ARRAY_INDEX, > > sent_seq, ip_id, > > + is_atomic); > > if (item_idx =3D=3D INVALID_ARRAY_INDEX) > > return -1; > > if (insert_new_flow(tbl, &key, item_idx) =3D=3D > > - INVALID_ARRAY_INDEX) { > > + INVALID_ARRAY_INDEX) { > > /* > > * Fail to insert a new flow, so delete the > > * stored packet. > > - */ > > - delete_item(tbl, item_idx, INVALID_ARRAY_INDEX); > > + */ > > + delete_tcp_item(tbl->items, item_idx, &tbl- > > >item_num, > > +INVALID_ARRAY_INDEX); > > return -1; > > } > > return 0; > > } > > + item_idx =3D tbl->flows[i].start_index; > > No need to update item_idx, and you can directly pass > tbl->flows[i].start_index to > gro_process_tcp_item(). And same in gro_tcp6_reassemble(). > > > > > - /* > > - * Check all packets in the flow and try to find a neighbor for > > - * the input packet. > > - */ > > - cur_idx =3D tbl->flows[i].start_index; > > - prev_idx =3D cur_idx; > > - do { > > - cmp =3D check_seq_option(&(tbl->items[cur_idx]), tcp_hdr, > > - sent_seq, ip_id, pkt->l4_len, tcp_dl, 0, > > - is_atomic); > > - if (cmp) { > > - if (merge_two_tcp4_packets(&(tbl->items[cur_idx])= , > > - pkt, cmp, sent_seq, ip_id= , > 0)) > > - return 1; > > - /* > > - * Fail to merge the two packets, as the packet > > - * length is greater than the max value. Store > > - * the packet into the flow. > > - */ > > - if (insert_new_item(tbl, pkt, start_time, cur_idx= , > > - sent_seq, ip_id, > is_atomic) =3D=3D > > - INVALID_ARRAY_INDEX) > > - return -1; > > - return 0; > > - } > > - prev_idx =3D cur_idx; > > - cur_idx =3D tbl->items[cur_idx].next_pkt_idx; > > - } while (cur_idx !=3D INVALID_ARRAY_INDEX); > > + return gro_process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items, > > item_idx, > > + &tbl->item_num, tbl- > > >max_item_num, > > + ip_id, is_atomic, > start_time); > > +} > > > > - /* Fail to find a neighbor, so store the packet into the flow. */ > > - if (insert_new_item(tbl, pkt, start_time, prev_idx, sent_seq, > > - ip_id, is_atomic) =3D=3D INVALID_ARRAY_IN= DEX) > > - return -1; > --000000000000189e1005fda1133c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Jiyau,

T= hanks for the quick review comments. Will address the review comments. Requ= ire clarification in one of the comments. Please find it inline.
=

= On Thu, Jun 8, 2023 at 9:35=E2=80=AFAM Hu, Jiayu <jiayu.hu@intel.com> wrote:
Hi Kumara,

Please see replies inline.

In addition, you need to update the programmer guide in generic_receive_off= load_lib.rst,
and release note release_23_07.rst.

Thanks,
Jiayu

> -----Original Message-----
> From: Kumara Parameshwaran <kumaraparamesh92@gmail.com>
> Sent: Tuesday, June 6, 2023 10:58 PM
> To: Hu, Jiayu <jiayu.hu@intel.com>
> Cc: dev@dpdk.org= ; Kumara Parameshwaran
> <ku= maraparamesh92@gmail.com>
> Subject: [PATCH v4] gro : ipv6 changes to support GRO for TCP/ipv6
>
> The patch adds GRO support for TCP/ipv6 packets. This does not include= the
> support for vxlan, udp ipv6 packets.
>
> Signed-off-by: Kumara Parameshwaran <kumaraparamesh92@gmail.com>> > diff --git a/lib/gro/gro_tcp.c b/lib/gro/gro_tcp.c new file mode 10064= 4 index
> 0000000000..02a7d0f8c5
> --- /dev/null
> +++ b/lib/gro/gro_tcp.c

For gro_tcp.c and gro_tcp.h, it's better to add "_internal" i= n the file name.

> @@ -0,0 +1,128 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2017 Intel Corporation
> + */
> +#include <rte_malloc.h>
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +
> +#include "gro_tcp.h"
> +
> +static inline uint32_t
> +find_an_empty_item(struct gro_tcp_item *items,
> +=C2=A0 =C2=A0 =C2=A0uint32_t max_item_num)
> +{
> +=C2=A0 =C2=A0 =C2=A0uint32_t i;
> +
> +=C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < max_item_num; i++)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (items[i].firstseg= =3D=3D NULL)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return i;
> +=C2=A0 =C2=A0 =C2=A0return INVALID_ARRAY_INDEX;
> +}
> +
> +uint32_t
> +insert_new_tcp_item(struct rte_mbuf *pkt,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct gro_tcp_item *= items,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *item_num, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t max_item_num= ,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t start_time,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t prev_idx, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t sent_seq, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t ip_id,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t is_atomic)
This function can be inline.

> +{
> +=C2=A0 =C2=A0 =C2=A0uint32_t item_idx;
> +
> +=C2=A0 =C2=A0 =C2=A0item_idx =3D find_an_empty_item(items, max_item_n= um);
> +=C2=A0 =C2=A0 =C2=A0if (item_idx =3D=3D INVALID_ARRAY_INDEX)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return INVALID_ARRAY_= INDEX;
> +
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].firstseg =3D pkt;
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].lastseg =3D rte_pktmbuf_lastseg(p= kt);
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].start_time =3D start_time;
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].next_pkt_idx =3D INVALID_ARRAY_IN= DEX;
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].sent_seq =3D sent_seq;
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].ip_id =3D ip_id;
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].nb_merged =3D 1;
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].is_atomic =3D is_atomic;
> +=C2=A0 =C2=A0 =C2=A0(*item_num) +=3D 1;
> +
> +=C2=A0 =C2=A0 =C2=A0/* if the previous packet exists, chain them toge= ther. */
> +=C2=A0 =C2=A0 =C2=A0if (prev_idx !=3D INVALID_ARRAY_INDEX) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0items[item_idx].next_= pkt_idx =3D
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0items[prev_idx].next_pkt_idx;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0items[prev_idx].next_= pkt_idx =3D item_idx;
> +=C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0return item_idx;
> +}
> +
> +uint32_t
> +delete_tcp_item(struct gro_tcp_item *items, uint32_t item_idx,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *item_num, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t prev_item_id= x)
> +{
> +=C2=A0 =C2=A0 =C2=A0uint32_t next_idx =3D items[item_idx].next_pkt_id= x;
> +
> +=C2=A0 =C2=A0 =C2=A0/* NULL indicates an empty item */
> +=C2=A0 =C2=A0 =C2=A0items[item_idx].firstseg =3D NULL;
> +=C2=A0 =C2=A0 =C2=A0(*item_num) -=3D 1;
> +=C2=A0 =C2=A0 =C2=A0if (prev_item_idx !=3D INVALID_ARRAY_INDEX)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0items[prev_item_idx].= next_pkt_idx =3D next_idx;
> +
> +=C2=A0 =C2=A0 =C2=A0return next_idx;
> +}

This function can be inline.

> +
> +int32_t
> +gro_process_tcp_item(struct rte_mbuf *pkt,
> +=C2=A0 =C2=A0 =C2=A0struct rte_tcp_hdr *tcp_hdr,
> +=C2=A0 =C2=A0 =C2=A0int32_t tcp_dl,
> +=C2=A0 =C2=A0 =C2=A0struct gro_tcp_item *items,
> +=C2=A0 =C2=A0 =C2=A0uint32_t item_idx,
> +=C2=A0 =C2=A0 =C2=A0uint32_t *item_num,
> +=C2=A0 =C2=A0 =C2=A0uint32_t max_item_num,
> +=C2=A0 =C2=A0 =C2=A0uint16_t ip_id,
> +=C2=A0 =C2=A0 =C2=A0uint8_t is_atomic,
> +=C2=A0 =C2=A0 =C2=A0uint64_t start_time)

It is for internal use, so it's better to remove "gro_" from = the function name.

> +{
> +=C2=A0 =C2=A0 =C2=A0uint32_t cur_idx;
> +=C2=A0 =C2=A0 =C2=A0uint32_t prev_idx;
> +=C2=A0 =C2=A0 =C2=A0int cmp;
> +=C2=A0 =C2=A0 =C2=A0uint32_t sent_seq;
> +
> +=C2=A0 =C2=A0 =C2=A0sent_seq =3D rte_be_to_cpu_32(tcp_hdr->sent_se= q);
> +=C2=A0 =C2=A0 =C2=A0/*
> +=C2=A0 =C2=A0 =C2=A0 * Check all packets in the flow and try to find = a neighbor for
> +=C2=A0 =C2=A0 =C2=A0 * the input packet.
> +=C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0cur_idx =3D item_idx;
> +=C2=A0 =C2=A0 =C2=A0prev_idx =3D cur_idx;
> +=C2=A0 =C2=A0 =C2=A0do {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmp =3D check_seq_opt= ion(&items[cur_idx], tcp_hdr,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sent_seq, ip_id, pkt->l4_len, tcp_dl,= 0,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is_atomic);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (cmp) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (merge_two_tcp_packets(&items[cur_idx],
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0pkt, cmp, sent_seq, ip_id, 0))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 1;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0/*
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 * Fail to merge the two packets, as the packet
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 * length is greater than the max value. Store
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 * the packet into the flow.
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (insert_new_tcp_item(pkt, items, item_num,
> max_item_num, start_time, cur_idx,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0sent_seq, ip_id, is_atomic) =3D=3D
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0INVALID_ARRA= Y_INDEX)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return 0;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0prev_idx =3D cur_idx;=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cur_idx =3D items[cur= _idx].next_pkt_idx;
> +=C2=A0 =C2=A0 =C2=A0} while (cur_idx !=3D INVALID_ARRAY_INDEX);
> +
> +=C2=A0 =C2=A0 =C2=A0/* Fail to find a neighbor, so store the packet i= nto the flow. */
> +=C2=A0 =C2=A0 =C2=A0if (insert_new_tcp_item(pkt, items, item_num, max= _item_num,
> start_time, prev_idx, sent_seq,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ip_id, is_atomic) =3D=3D INVALID_ARRAY_I= NDEX)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0return 0;
> +}
> diff --git a/lib/gro/gro_tcp.h b/lib/gro/gro_tcp.h new file mode 10064= 4 index
> 0000000000..4b5b4eda9c
> --- /dev/null
> +++ b/lib/gro/gro_tcp.h
> @@ -0,0 +1,209 @@
> +#ifndef _GRO_TCP_H_
> +#define _GRO_TCP_H_
> +
> +#define INVALID_ARRAY_INDEX 0xffffffffUL
> +
> +#include <rte_tcp.h>
> +
> +/*
> + * The max length of a IPv4 packet, which includes the length of the = L3
> + * header, the L4 header and the data payload.
> + */
> +#define MAX_IP_PKT_LENGTH UINT16_MAX
> +
> +/* The maximum TCP header length */
> +#define MAX_TCP_HLEN 60
> +#define INVALID_TCP_HDRLEN(len) \
> +=C2=A0 =C2=A0 =C2=A0(((len) < sizeof(struct rte_tcp_hdr)) || ((len= ) > MAX_TCP_HLEN))
> +
> +struct gro_tcp_flow {

This structure name is confusing. In the upper layer, tcp4 and tcp6 have gr= o_tcp4_flow
and gro_tcp6_flow, which represent a flow. Inside gro_tcp4/6_flow, there ar= e keys,
represented by struct tcp4/6_flow_key. But inside struct tcp4/6_flow_key, t= here is
struct gro_tcp_flow. Need to rename struct gro_tcp_flow, like common_tcp_fl= ow_key.

> +=C2=A0 =C2=A0 =C2=A0struct rte_ether_addr eth_saddr;
> +=C2=A0 =C2=A0 =C2=A0struct rte_ether_addr eth_daddr;
> +=C2=A0 =C2=A0 =C2=A0uint32_t recv_ack;
> +=C2=A0 =C2=A0 =C2=A0uint16_t src_port;
> +=C2=A0 =C2=A0 =C2=A0uint16_t dst_port;
> +};
> +
> +#define ASSIGN_TCP_FLOW_KEY(k1, k2) \

Ditto. The macro needs rename, like ASSIGN_COMMON_TCP_FLOW_KEY.

> +=C2=A0 =C2=A0 =C2=A0do {\
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&= amp;(k1->eth_saddr), &(k2->eth_saddr)); \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&= amp;(k1->eth_daddr), &(k2->eth_daddr));
> \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0k2->recv_ack =3D k= 1->recv_ack; \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0k2->src_port =3D k= 1->src_port; \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0k2->dst_port =3D k= 1->dst_port; \
> +=C2=A0 =C2=A0 =C2=A0} while (0)
> +
> +struct gro_tcp_item {
> +=C2=A0 =C2=A0 =C2=A0/*
> +=C2=A0 =C2=A0 =C2=A0 * The first MBUF segment of the packet. If the v= alue
> +=C2=A0 =C2=A0 =C2=A0 * is NULL, it means the item is empty.
> +=C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0struct rte_mbuf *firstseg;
> +=C2=A0 =C2=A0 =C2=A0/* The last MBUF segment of the packet */
> +=C2=A0 =C2=A0 =C2=A0struct rte_mbuf *lastseg;
> +=C2=A0 =C2=A0 =C2=A0/*
> +=C2=A0 =C2=A0 =C2=A0 * The time when the first packet is inserted int= o the table.
> +=C2=A0 =C2=A0 =C2=A0 * This value won't be updated, even if the p= acket is merged
> +=C2=A0 =C2=A0 =C2=A0 * with other packets.
> +=C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0uint64_t start_time;
> +=C2=A0 =C2=A0 =C2=A0/*
> +=C2=A0 =C2=A0 =C2=A0 * next_pkt_idx is used to chain the packets that=
> +=C2=A0 =C2=A0 =C2=A0 * are in the same flow but can't be merged t= ogether
> +=C2=A0 =C2=A0 =C2=A0 * (e.g. caused by packet reordering).
> +=C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0uint32_t next_pkt_idx;
> +=C2=A0 =C2=A0 =C2=A0/* TCP sequence number of the packet */
> +=C2=A0 =C2=A0 =C2=A0uint32_t sent_seq;
> +=C2=A0 =C2=A0 =C2=A0/* IPv4 ID of the packet */
> +=C2=A0 =C2=A0 =C2=A0uint16_t ip_id;

The ip_id field is not used by tcp6. It's better to use an union to inc= lude ip_id for IPv4 and
an useless member for IPv6 with some comments to avoid confusing.

> +=C2=A0 =C2=A0 =C2=A0/* the number of merged packets */
> +=C2=A0 =C2=A0 =C2=A0uint16_t nb_merged;
> +=C2=A0 =C2=A0 =C2=A0/* Indicate if IPv4 ID can be ignored */
> +=C2=A0 =C2=A0 =C2=A0uint8_t is_atomic;
> +};
> +
> +uint32_t
> +insert_new_tcp_item(struct rte_mbuf *pkt,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct gro_tcp_item *= items,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *item_num, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t table_size,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t start_time,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t prev_idx, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t sent_seq, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t ip_id,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t is_atomic); > +
> +uint32_t
> +delete_tcp_item(struct gro_tcp_item *items,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t item_idx, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *item_num, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t prev_item_id= x);
> +
> +int32_t
> +gro_process_tcp_item(struct rte_mbuf *pkt,
> +=C2=A0 =C2=A0 =C2=A0struct rte_tcp_hdr *tcp_hdr,
> +=C2=A0 =C2=A0 =C2=A0int32_t tcp_dl,
> +=C2=A0 =C2=A0 =C2=A0struct gro_tcp_item *items,
> +=C2=A0 =C2=A0 =C2=A0uint32_t item_idx,
> +=C2=A0 =C2=A0 =C2=A0uint32_t *item_num,
> +=C2=A0 =C2=A0 =C2=A0uint32_t table_size,
> +=C2=A0 =C2=A0 =C2=A0uint16_t ip_id,
> +=C2=A0 =C2=A0 =C2=A0uint8_t is_atomic,
> +=C2=A0 =C2=A0 =C2=A0uint64_t start_time);
> +
> +/*
> + * Merge two TCP packets without updating checksums.
> + * If cmp is larger than 0, append the new packet to the
> + * original packet. Otherwise, pre-pend the new packet to
> + * the original packet.
> + */
> +static inline int
> +merge_two_tcp_packets(struct gro_tcp_item *item,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct rte_mbuf *pkt,=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int cmp,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t sent_seq, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t ip_id,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t l2_offset) > +{
> +=C2=A0 =C2=A0 =C2=A0struct rte_mbuf *pkt_head, *pkt_tail, *lastseg; > +=C2=A0 =C2=A0 =C2=A0uint16_t hdr_len, l2_len;
> +
> +=C2=A0 =C2=A0 =C2=A0if (cmp > 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pkt_head =3D item->= ;firstseg;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pkt_tail =3D pkt;
> +=C2=A0 =C2=A0 =C2=A0} else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pkt_head =3D pkt;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pkt_tail =3D item->= ;firstseg;
> +=C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0/* check if the IPv4 packet length is greater tha= n the max value */
> +=C2=A0 =C2=A0 =C2=A0hdr_len =3D l2_offset + pkt_head->l2_len + pkt= _head->l3_len +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pkt_head->l4_len;<= br> > +=C2=A0 =C2=A0 =C2=A0l2_len =3D l2_offset > 0 ? pkt_head->outer_= l2_len : pkt_head->l2_len;
> +=C2=A0 =C2=A0 =C2=A0if (unlikely(pkt_head->pkt_len - l2_len + pkt_= tail->pkt_len -
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0hdr_len > MAX_IP_PKT_LENGTH))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0;
> +
> +=C2=A0 =C2=A0 =C2=A0/* remove the packet header for the tail packet *= /
> +=C2=A0 =C2=A0 =C2=A0rte_pktmbuf_adj(pkt_tail, hdr_len);
> +
> +=C2=A0 =C2=A0 =C2=A0/* chain two packets together */
> +=C2=A0 =C2=A0 =C2=A0if (cmp > 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item->lastseg->= next =3D pkt;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item->lastseg =3D = rte_pktmbuf_lastseg(pkt);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* update IP ID to th= e larger value */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item->ip_id =3D ip= _id;
> +=C2=A0 =C2=A0 =C2=A0} else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0lastseg =3D rte_pktmb= uf_lastseg(pkt);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0lastseg->next =3D = item->firstseg;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item->firstseg =3D= pkt;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* update sent_seq to= the smaller value */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item->sent_seq =3D= sent_seq;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item->ip_id =3D ip= _id;
> +=C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0item->nb_merged++;
> +
> +=C2=A0 =C2=A0 =C2=A0/* update MBUF metadata for the merged packet */<= br> > +=C2=A0 =C2=A0 =C2=A0pkt_head->nb_segs +=3D pkt_tail->nb_segs; > +=C2=A0 =C2=A0 =C2=A0pkt_head->pkt_len +=3D pkt_tail->pkt_len; > +
> +=C2=A0 =C2=A0 =C2=A0return 1;
> +}
> +
> +/*
> + * Check if two TCP/IPv4 packets are neighbors.
> + */
> +static inline int
> +check_seq_option(struct gro_tcp_item *item,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct rte_tcp_hdr *t= cph,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t sent_seq, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t ip_id,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t tcp_hl,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t tcp_dl,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t l2_offset, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t is_atomic) > +{
> +=C2=A0 =C2=A0 =C2=A0struct rte_mbuf *pkt_orig =3D item->firstseg;<= br> > +=C2=A0 =C2=A0 =C2=A0char *iph_orig;
> +=C2=A0 =C2=A0 =C2=A0struct rte_tcp_hdr *tcph_orig;
> +=C2=A0 =C2=A0 =C2=A0uint16_t len, tcp_hl_orig;
> +
> +=C2=A0 =C2=A0 =C2=A0iph_orig =3D (char *)(rte_pktmbuf_mtod(pkt_orig, = char *) +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0l2_offset + pkt_orig->l2_len);
> +=C2=A0 =C2=A0 =C2=A0tcph_orig =3D (struct rte_tcp_hdr *)(iph_orig + p= kt_orig->l3_len);
> +=C2=A0 =C2=A0 =C2=A0tcp_hl_orig =3D pkt_orig->l4_len;
> +
> +=C2=A0 =C2=A0 =C2=A0/* Check if TCP option fields equal */
> +=C2=A0 =C2=A0 =C2=A0len =3D RTE_MAX(tcp_hl, tcp_hl_orig) - sizeof(str= uct rte_tcp_hdr);
> +=C2=A0 =C2=A0 =C2=A0if ((tcp_hl !=3D tcp_hl_orig) || ((len > 0) &a= mp;&
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(memcmp(tcph + 1, tcph_orig + 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0len) !=3D 0)= ))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0;
> +
> +=C2=A0 =C2=A0 =C2=A0/* Don't merge packets whose DF bits are diff= erent */
> +=C2=A0 =C2=A0 =C2=A0if (unlikely(item->is_atomic ^ is_atomic))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0;
> +
> +=C2=A0 =C2=A0 =C2=A0/* check if the two packets are neighbors */
> +=C2=A0 =C2=A0 =C2=A0len =3D pkt_orig->pkt_len - l2_offset - pkt_or= ig->l2_len -
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pkt_orig->l3_len -= tcp_hl_orig;
> +=C2=A0 =C2=A0 =C2=A0if ((sent_seq =3D=3D item->sent_seq + len) &am= p;& (is_atomic ||
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(ip_id =3D=3D item->ip_id + 1)))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* append the new pac= ket */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 1;
> +=C2=A0 =C2=A0 =C2=A0else if ((sent_seq + tcp_dl =3D=3D item->sent_= seq) && (is_atomic ||
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(ip_id + item->nb_merged =3D=3D item-= >ip_id)))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* pre-pend the new p= acket */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0return 0;
> +}
> +
> +static inline int
> +is_same_tcp_flow(struct gro_tcp_flow *k1, struct gro_tcp_flow *k2) {<= br> > +=C2=A0 =C2=A0 =C2=A0return (!memcmp(k1, k2, sizeof(struct gro_tcp_flo= w))); }

I think this function needs rename, as the result of this function cannot i= dentify if they are
same TCP flow.

> +
> +#endif
> diff --git a/lib/gro/gro_tcp4.c b/lib/gro/gro_tcp4.c index
> 0014096e63..ffc33747c4 100644
> --- a/lib/gro/gro_tcp4.c
> +++ b/lib/gro/gro_tcp4.c
> @@ -7,6 +7,7 @@
>=C2=A0 #include <rte_ethdev.h>
>
>=C2=A0 #include "gro_tcp4.h"
> +#include "gro_tcp.h"
>
>=C2=A0 void *
>=C2=A0 gro_tcp4_tbl_create(uint16_t socket_id, @@ -30,7 +31,7 @@
> gro_tcp4_tbl_create(uint16_t socket_id,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (tbl =3D=3D NULL)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return NULL;
>
> -=C2=A0 =C2=A0 =C2=A0size =3D sizeof(struct gro_tcp4_item) * entries_n= um;
> +=C2=A0 =C2=A0 =C2=A0size =3D sizeof(struct gro_tcp_item) * entries_nu= m;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0tbl->items =3D rte_zmalloc_socket(__func_= _,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0size,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0RTE_CACHE_LINE_SIZE,
> @@ -71,18 +72,6 @@ gro_tcp4_tbl_destroy(void *tbl)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0rte_free(tcp_tbl);
>=C2=A0 }
>
> -static inline uint32_t
> -find_an_empty_item(struct gro_tcp4_tbl *tbl) -{
> -=C2=A0 =C2=A0 =C2=A0uint32_t i;
> -=C2=A0 =C2=A0 =C2=A0uint32_t max_item_num =3D tbl->max_item_num; > -
> -=C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < max_item_num; i++)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (tbl->items[i].= firstseg =3D=3D NULL)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return i;
> -=C2=A0 =C2=A0 =C2=A0return INVALID_ARRAY_INDEX;
> -}
> -
>=C2=A0 static inline uint32_t
>=C2=A0 find_an_empty_flow(struct gro_tcp4_tbl *tbl)=C2=A0 { @@ -95,56 += 84,6 @@
> find_an_empty_flow(struct gro_tcp4_tbl *tbl)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return INVALID_ARRAY_INDEX;
>=C2=A0 }
>
> -static inline uint32_t
> -insert_new_item(struct gro_tcp4_tbl *tbl,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct rte_mbuf *pkt,=
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t start_time,<= br> > -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t prev_idx, > -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t sent_seq, > -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t ip_id,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t is_atomic) > -{
> -=C2=A0 =C2=A0 =C2=A0uint32_t item_idx;
> -
> -=C2=A0 =C2=A0 =C2=A0item_idx =3D find_an_empty_item(tbl);
> -=C2=A0 =C2=A0 =C2=A0if (item_idx =3D=3D INVALID_ARRAY_INDEX)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return INVALID_ARRAY_= INDEX;
> -
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].firstseg =3D pkt;
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].lastseg =3D rte_pktmbuf_l= astseg(pkt);
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].start_time =3D start_time= ;
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].next_pkt_idx =3D INVALID_= ARRAY_INDEX;
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].sent_seq =3D sent_seq; > -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].ip_id =3D ip_id;
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].nb_merged =3D 1;
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].is_atomic =3D is_atomic;<= br> > -=C2=A0 =C2=A0 =C2=A0tbl->item_num++;
> -
> -=C2=A0 =C2=A0 =C2=A0/* if the previous packet exists, chain them toge= ther. */
> -=C2=A0 =C2=A0 =C2=A0if (prev_idx !=3D INVALID_ARRAY_INDEX) {
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tbl->items[item_id= x].next_pkt_idx =3D
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0tbl->items[prev_idx].next_pkt_idx;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tbl->items[prev_id= x].next_pkt_idx =3D item_idx;
> -=C2=A0 =C2=A0 =C2=A0}
> -
> -=C2=A0 =C2=A0 =C2=A0return item_idx;
> -}
> -
> -static inline uint32_t
> -delete_item(struct gro_tcp4_tbl *tbl, uint32_t item_idx,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t prev_item_id= x)
> -{
> -=C2=A0 =C2=A0 =C2=A0uint32_t next_idx =3D tbl->items[item_idx].nex= t_pkt_idx;
> -
> -=C2=A0 =C2=A0 =C2=A0/* NULL indicates an empty item */
> -=C2=A0 =C2=A0 =C2=A0tbl->items[item_idx].firstseg =3D NULL;
> -=C2=A0 =C2=A0 =C2=A0tbl->item_num--;
> -=C2=A0 =C2=A0 =C2=A0if (prev_item_idx !=3D INVALID_ARRAY_INDEX)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tbl->items[prev_it= em_idx].next_pkt_idx =3D next_idx;
> -
> -=C2=A0 =C2=A0 =C2=A0return next_idx;
> -}
> -
>=C2=A0 static inline uint32_t
>=C2=A0 insert_new_flow(struct gro_tcp4_tbl *tbl,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct tcp4_flow= _key *src,
> @@ -159,13 +98,10 @@ insert_new_flow(struct gro_tcp4_tbl *tbl,
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0dst =3D &(tbl->flows[flow_idx].key);<= br> >
> -=C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&(src->eth_saddr), &am= p;(dst->eth_saddr));
> -=C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&(src->eth_daddr), &am= p;(dst->eth_daddr));
> +=C2=A0 =C2=A0 =C2=A0ASSIGN_TCP_FLOW_KEY((&src->tcp_flow), (&am= p;dst->tcp_flow));
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0dst->ip_src_addr =3D src->ip_src_addr;=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0dst->ip_dst_addr =3D src->ip_dst_addr;=
> -=C2=A0 =C2=A0 =C2=A0dst->recv_ack =3D src->recv_ack;
> -=C2=A0 =C2=A0 =C2=A0dst->src_port =3D src->src_port;
> -=C2=A0 =C2=A0 =C2=A0dst->dst_port =3D src->dst_port;
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0tbl->flows[flow_idx].start_index =3D item= _idx;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0tbl->flow_num++;
> @@ -173,21 +109,6 @@ insert_new_flow(struct gro_tcp4_tbl *tbl,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return flow_idx;
>=C2=A0 }
>
> -/*
> - * update the packet length for the flushed packet.
> - */
> -static inline void
> -update_header(struct gro_tcp4_item *item) -{
> -=C2=A0 =C2=A0 =C2=A0struct rte_ipv4_hdr *ipv4_hdr;
> -=C2=A0 =C2=A0 =C2=A0struct rte_mbuf *pkt =3D item->firstseg;
> -
> -=C2=A0 =C2=A0 =C2=A0ipv4_hdr =3D (struct rte_ipv4_hdr *)(rte_pktmbuf_= mtod(pkt, char *) +
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0pkt->l2_len);
> -=C2=A0 =C2=A0 =C2=A0ipv4_hdr->total_length =3D rte_cpu_to_be_16(pk= t->pkt_len -
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0pkt->l2_len);
> -}
> -
>=C2=A0 int32_t
>=C2=A0 gro_tcp4_reassemble(struct rte_mbuf *pkt,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct gro_tcp4_= tbl *tbl,
> @@ -195,16 +116,15 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,=C2=A0 = {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0struct rte_ether_hdr *eth_hdr;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0struct rte_ipv4_hdr *ipv4_hdr;
> -=C2=A0 =C2=A0 =C2=A0struct rte_tcp_hdr *tcp_hdr;
> -=C2=A0 =C2=A0 =C2=A0uint32_t sent_seq;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0int32_t tcp_dl;
> +=C2=A0 =C2=A0 =C2=A0struct rte_tcp_hdr *tcp_hdr;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t ip_id, hdr_len, frag_off, ip_tlen;<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t is_atomic;
> +=C2=A0 =C2=A0 =C2=A0uint32_t sent_seq;

No need to change tcp_hdr and sent_seq here.
The flow matching is done in the function and if the= flow is not found insert_new_tcp_item is invoked from this function itself= . Did you mean to move that to the process_tcp_item as well? If that is the= case we should pass the start_idx as INVALID_ARRAY_INDEX and in process_tc= p_item check if INVALID_ARRAY_INDEX do a insert_new_tcp_item and return, do= not do the sequnce number checks etc.
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0struct tcp4_flow_key key;
> -=C2=A0 =C2=A0 =C2=A0uint32_t cur_idx, prev_idx, item_idx;
> +=C2=A0 =C2=A0 =C2=A0uint32_t item_idx;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t i, max_flow_num, remaining_flow_num= ;
> -=C2=A0 =C2=A0 =C2=A0int cmp;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t find;
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/*
> @@ -216,7 +136,7 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0eth_hdr =3D rte_pktmbuf_mtod(pkt, struct rte= _ether_hdr *);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0ipv4_hdr =3D (struct rte_ipv4_hdr *)((char *= )eth_hdr + pkt->l2_len);
> -=C2=A0 =C2=A0 =C2=A0tcp_hdr =3D (struct rte_tcp_hdr *)((char *)ipv4_h= dr + pkt->l3_len);
> +=C2=A0 =C2=A0 =C2=A0tcp_hdr =3D rte_pktmbuf_mtod_offset(pkt, struct r= te_tcp_hdr *,
> +pkt->l2_len + pkt->l3_len);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0hdr_len =3D pkt->l2_len + pkt->l3_len = + pkt->l4_len;
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/*
> @@ -230,7 +150,6 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0ip_tlen =3D rte_be_to_cpu_16(ipv4_hdr->to= tal_length);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (pkt->pkt_len > (uint32_t)(ip_tlen = + pkt->l2_len))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rte_pktmbuf_trim= (pkt, pkt->pkt_len - ip_tlen - pkt->l2_len);
> -
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/*
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 * Don't process the packet whose payloa= d length is less than or
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 * equal to 0.
> @@ -239,6 +158,13 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (tcp_dl <=3D 0)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
>
> +=C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&(eth_hdr->src_addr),<= br> > &(key.tcp_flow.eth_saddr));
> +=C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&(eth_hdr->dst_addr),<= br> > &(key.tcp_flow.eth_daddr));
> +=C2=A0 =C2=A0 =C2=A0key.ip_src_addr =3D ipv4_hdr->src_addr;
> +=C2=A0 =C2=A0 =C2=A0key.ip_dst_addr =3D ipv4_hdr->dst_addr;
> +=C2=A0 =C2=A0 =C2=A0key.tcp_flow.src_port =3D tcp_hdr->src_port; > +=C2=A0 =C2=A0 =C2=A0key.tcp_flow.dst_port =3D tcp_hdr->dst_port; > +=C2=A0 =C2=A0 =C2=A0key.tcp_flow.recv_ack =3D tcp_hdr->recv_ack; >=C2=A0 =C2=A0 =C2=A0 =C2=A0/*
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 * Save IPv4 ID for the packet whose DF bit = is 0. For the packet
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 * whose DF bit is 1, IPv4 ID is ignored. > @@ -246,15 +172,6 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0frag_off =3D rte_be_to_cpu_16(ipv4_hdr->f= ragment_offset);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0is_atomic =3D (frag_off & RTE_IPV4_HDR_D= F_FLAG) =3D=3D
> RTE_IPV4_HDR_DF_FLAG;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0ip_id =3D is_atomic ? 0 : rte_be_to_cpu_16(i= pv4_hdr->packet_id);
> -=C2=A0 =C2=A0 =C2=A0sent_seq =3D rte_be_to_cpu_32(tcp_hdr->sent_se= q);
> -
> -=C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&(eth_hdr->src_addr), = &(key.eth_saddr));
> -=C2=A0 =C2=A0 =C2=A0rte_ether_addr_copy(&(eth_hdr->dst_addr), = &(key.eth_daddr));
> -=C2=A0 =C2=A0 =C2=A0key.ip_src_addr =3D ipv4_hdr->src_addr;
> -=C2=A0 =C2=A0 =C2=A0key.ip_dst_addr =3D ipv4_hdr->dst_addr;
> -=C2=A0 =C2=A0 =C2=A0key.src_port =3D tcp_hdr->src_port;
> -=C2=A0 =C2=A0 =C2=A0key.dst_port =3D tcp_hdr->dst_port;
> -=C2=A0 =C2=A0 =C2=A0key.recv_ack =3D tcp_hdr->recv_ack;
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Search for a matched flow. */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0max_flow_num =3D tbl->max_flow_num;
> @@ -270,63 +187,44 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>
> -=C2=A0 =C2=A0 =C2=A0/*
> -=C2=A0 =C2=A0 =C2=A0 * Fail to find a matched flow. Insert a new flow= and store the
> -=C2=A0 =C2=A0 =C2=A0 * packet into the flow.
> -=C2=A0 =C2=A0 =C2=A0 */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (find =3D=3D 0) {
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item_idx =3D insert_n= ew_item(tbl, pkt, start_time,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0INVALID_ARRAY_INDEX, sent_seq, ip_id, > -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is_atomic);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sent_seq =3D rte_be_t= o_cpu_32(tcp_hdr->sent_seq);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0item_idx =3D insert_n= ew_tcp_item(pkt, tbl->items, &tbl-
> >item_num, tbl->max_item_num, start_time,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0INVALID_ARRAY_INDEX,
> sent_seq, ip_id,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0is_atomic);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (item_idx =3D= =3D INVALID_ARRAY_INDEX)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0return -1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (insert_new_f= low(tbl, &key, item_idx) =3D=3D
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0INVALID_ARRAY_INDEX) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0INVALID_ARRAY_INDEX) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0/*
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 * Fail to insert a new flow, so delete the
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 * stored packet.
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 */
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0delete_item(tbl, item_idx, INVALID_ARRAY_INDEX);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0*/
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0delete_tcp_item(tbl->items, item_idx, &tbl-
> >item_num,
> +INVALID_ARRAY_INDEX);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0return -1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0item_idx =3D tbl->flows[i].start_index;

No need to update item_idx, and you can directly pass tbl->flows[i].star= t_index to
gro_process_tcp_item(). And same in gro_tcp6_reassemble().

>
> -=C2=A0 =C2=A0 =C2=A0/*
> -=C2=A0 =C2=A0 =C2=A0 * Check all packets in the flow and try to find = a neighbor for
> -=C2=A0 =C2=A0 =C2=A0 * the input packet.
> -=C2=A0 =C2=A0 =C2=A0 */
> -=C2=A0 =C2=A0 =C2=A0cur_idx =3D tbl->flows[i].start_index;
> -=C2=A0 =C2=A0 =C2=A0prev_idx =3D cur_idx;
> -=C2=A0 =C2=A0 =C2=A0do {
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmp =3D check_seq_opt= ion(&(tbl->items[cur_idx]), tcp_hdr,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sent_seq, ip_id, pkt->l4_len, tcp_dl,= 0,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is_atomic);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (cmp) {
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (merge_two_tcp4_packets(&(tbl->items[cur_idx]),
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0pkt, cmp, sent_seq, ip_id, 0))
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 1;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0/*
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 * Fail to merge the two packets, as the packet
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 * length is greater than the max value. Store
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 * the packet into the flow.
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 */
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (insert_new_item(tbl, pkt, start_time, cur_idx,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0sent_seq, ip_id, is_atomic) =3D=3D
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0INVALID_ARRA= Y_INDEX)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return 0;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0prev_idx =3D cur_idx;=
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cur_idx =3D tbl->i= tems[cur_idx].next_pkt_idx;
> -=C2=A0 =C2=A0 =C2=A0} while (cur_idx !=3D INVALID_ARRAY_INDEX);
> +=C2=A0 =C2=A0 =C2=A0return gro_process_tcp_item(pkt, tcp_hdr, tcp_dl,= tbl->items,
> item_idx,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0&tbl->item_num, tbl-
> >max_item_num,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0ip_id, is_atomic, start_time);
> +}
>
> -=C2=A0 =C2=A0 =C2=A0/* Fail to find a neighbor, so store the packet i= nto the flow. */
> -=C2=A0 =C2=A0 =C2=A0if (insert_new_item(tbl, pkt, start_time, prev_id= x, sent_seq,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ip_id, is_atomic) =3D=3D INVALID_ARRAY_I= NDEX)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
--000000000000189e1005fda1133c--