<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jan 18, 2024 at 1:40 AM Kumara Parameshwaran <<a href="mailto:kumaraparamesh92@gmail.com">kumaraparamesh92@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>In the current implementation when a packet is received with<br>
special TCP flag(s) set, only that packet is delivered out of order.<br>
There could be already coalesced packets in the GRO table<br>
belonging to the same flow but not delivered.<br>
This fix makes sure that the entire segment is delivered with the<br>
special flag(s) set which is how the Linux GRO is also implemented<br>
<br>
Signed-off-by: Kumara Parameshwaran <<a href="mailto:kumaraparamesh92@gmail.com" target="_blank">kumaraparamesh92@gmail.com</a>><br>
Co-authored-by: Kumara Parameshwaran <<a href="mailto:krathinavel@microsoft.com" target="_blank">krathinavel@microsoft.com</a>><br>
---<br>
        If the received packet is not a pure ACK packet, we check if<br>
        there are any previous packets in the flow, if present we indulge<br>
        the received packet also in the coalescing logic and update the flags<br>
        of the last recived packet to the entire segment which would avoid<br>
        re-ordering.<br>
<br>
        Lets say a case where P1(PSH), P2(ACK), P3(ACK)  are received in burst mode,<br>
        P1 contains PSH flag and since it does not contain any prior packets in the flow<br>
        we copy it to unprocess_packets and P2(ACK) and P3(ACK) are merged together.<br>
        In the existing case the  P2,P3 would be delivered as single segment first and the<br>
        unprocess_packets will be copied later which will cause reordering. With the patch<br>
        copy the unprocess packets first and then the packets from the GRO table.<br>
<br>
        Testing done<br>
        The csum test-pmd was modified to support the following<br>
        GET request of 10MB from client to server via test-pmd (static arp entries added in client<br>
        and server). Enable GRO and TSO in test-pmd where the packets recived from the client mac<br>
        would be sent to server mac and vice versa.<br>
        In above testing, without the patch the client observerd re-ordering of 25 packets<br>
        and with the patch there were no packet re-ordering observerd.<br>
<br>
v2: <br>
        Fix warnings in commit and comment.<br>
        Do not consider packet as candidate to merge if it contains SYN/RST flag.<br>
<br>
v3:<br>
        Fix warnings.<br>
<br>
v4:<br>
        Rebase with master.<br>
<br>
v5:<br>
        Adding co-author email<br>
v6:<br>
        Address review comments from the maintainer to restructure the code <br>
        and handle only special flags PSH,FIN<br>
<br>
v7:<br>
        Fix warnings and errors<br>
<br>
v8:<br>
        Fix warnings and errors<br>
<br>
v9:<br>
        Fix commit message <br>
<br>
 lib/gro/gro_tcp.h  | 11 ++++++++<br>
 lib/gro/gro_tcp4.c | 67 +++++++++++++++++++++++++++++-----------------<br>
 2 files changed, 54 insertions(+), 24 deletions(-)<br>
<br>
diff --git a/lib/gro/gro_tcp.h b/lib/gro/gro_tcp.h<br>
index d926c4b8cc..137a03bc96 100644<br>
--- a/lib/gro/gro_tcp.h<br>
+++ b/lib/gro/gro_tcp.h<br>
@@ -187,4 +187,15 @@ is_same_common_tcp_key(struct cmn_tcp_key *k1, struct cmn_tcp_key *k2)<br>
        return (!memcmp(k1, k2, sizeof(struct cmn_tcp_key)));<br>
 }<br>
<br>
+static inline void<br>
+update_tcp_hdr_flags(struct rte_tcp_hdr *tcp_hdr, struct rte_mbuf *pkt)<br>
+{<br>
+       struct rte_tcp_hdr *merged_tcp_hdr;<br>
+<br>
+       merged_tcp_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_tcp_hdr *, pkt->l2_len +<br>
+                                                       pkt->l3_len);<br>
+       merged_tcp_hdr->tcp_flags |= tcp_hdr->tcp_flags;<br>
+<br>
+}<br>
+<br>
 #endif<br>
diff --git a/lib/gro/gro_tcp4.c b/lib/gro/gro_tcp4.c<br>
index 6645de592b..8af5a8d8a9 100644<br>
--- a/lib/gro/gro_tcp4.c<br>
+++ b/lib/gro/gro_tcp4.c<br>
@@ -126,6 +126,7 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,<br>
        uint32_t item_idx;<br>
        uint32_t i, max_flow_num, remaining_flow_num;<br>
        uint8_t find;<br>
+       uint32_t item_start_idx;<br>
<br>
        /*<br>
         * Don't process the packet whose TCP header length is greater<br>
@@ -139,13 +140,6 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,<br>
        tcp_hdr = (struct rte_tcp_hdr *)((char *)ipv4_hdr + pkt->l3_len);<br>
        hdr_len = pkt->l2_len + pkt->l3_len + pkt->l4_len;<br>
<br>
-       /*<br>
-        * Don't process the packet which has FIN, SYN, RST, PSH, URG, ECE<br>
-        * or CWR set.<br>
-        */<br>
-       if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG)<br>
-               return -1;<br>
-<br>
        /* trim the tail padding bytes */<br>
        ip_tlen = rte_be_to_cpu_16(ipv4_hdr->total_length);<br>
        if (pkt->pkt_len > (uint32_t)(ip_tlen + pkt->l2_len))<br>
@@ -183,6 +177,7 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,<br>
                if (tbl->flows[i].start_index != INVALID_ARRAY_INDEX) {<br>
                        if (is_same_tcp4_flow(tbl->flows[i].key, key)) {<br>
                                find = 1;<br>
+                               item_start_idx = tbl->flows[i].start_index;<br>
                                break;<br>
                        }<br>
                        remaining_flow_num--;<br>
@@ -190,28 +185,52 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,<br>
        }<br>
<br>
        if (find == 0) {<br>
-               sent_seq = rte_be_to_cpu_32(tcp_hdr->sent_seq);<br>
-               item_idx = insert_new_tcp_item(pkt, tbl->items, &tbl->item_num,<br>
-                                               tbl->max_item_num, start_time,<br>
-                                               INVALID_ARRAY_INDEX, sent_seq, ip_id,<br>
-                                               is_atomic);<br>
-               if (item_idx == INVALID_ARRAY_INDEX)<br>
+               /*<br>
+                * Add new flow to the table only if contains ACK flag with data.<br>
+                * Do not add any packets with additional tcp flags to the GRO table<br>
+                */<br>
+               if (tcp_hdr->tcp_flags == RTE_TCP_ACK_FLAG) {<br>
+                       sent_seq = rte_be_to_cpu_32(tcp_hdr->sent_seq);<br>
+                       item_idx = insert_new_tcp_item(pkt, tbl->items, &tbl->item_num,<br>
+                                                       tbl->max_item_num, start_time,<br>
+                                                       INVALID_ARRAY_INDEX, sent_seq, ip_id,<br>
+                                                       is_atomic);<br>
+                       if (item_idx == INVALID_ARRAY_INDEX)<br>
+                               return -1;<br>
+                       if (insert_new_flow(tbl, &key, item_idx) ==<br>
+                               INVALID_ARRAY_INDEX) {<br>
+                               /*<br>
+                                * Fail to insert a new flow, so delete the<br>
+                                * stored packet.<br>
+                                */<br>
+                               delete_tcp_item(tbl->items, item_idx, &tbl->item_num,<br>
+                                       INVALID_ARRAY_INDEX);<br>
+                               return -1;<br>
+                       }<br>
+                       return 0;<br>
+               } else {<br>
                        return -1;<br>
-               if (insert_new_flow(tbl, &key, item_idx) ==<br>
-                       INVALID_ARRAY_INDEX) {<br>
-                       /*<br>
-                        * Fail to insert a new flow, so delete the<br>
-                        * stored packet.<br>
-                       */<br>
-                       delete_tcp_item(tbl->items, item_idx, &tbl->item_num, INVALID_ARRAY_INDEX);<br>
+               }<br>
+       } else {<br>
+               /*<br>
+                * Any packet with additional flags like PSH,FIN should be processed<br>
+                * and flushed immediately.<br>
+                * Hence marking the start time to 0, so that the packets will be flushed<br>
+                * immediately in timer mode.<br>
+                */<br>
+               if (tcp_hdr->tcp_flags & (RTE_TCP_ACK_FLAG|RTE_TCP_PSH_FLAG|RTE_TCP_FIN_FLAG)) {<br>
+                       if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG)<br>
+                               tbl->items[item_start_idx].start_time = 0;<br>
+                       return process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items,<br>
+                                               tbl->flows[i].start_index,<br>
+                                               &tbl->item_num, tbl->max_item_num,<br>
+                                               ip_id, is_atomic, start_time);<br>
+               } else {<br>
                        return -1;<br>
                }<br>
-               return 0;<br>
        }<br>
<br>
-       return process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items, tbl->flows[i].start_index,<br>
-                                               &tbl->item_num, tbl->max_item_num,<br>
-                                               ip_id, is_atomic, start_time);<br>
+       return -1;<br>
 }<br>
<br>
 /*<br>
-- <br>
2.34.1<br></div>
>> Please ignore. <br>
</blockquote></div></div>