From 33a6e9435222151446c54a93696ed2c417dc15be Mon Sep 17 00:00:00 2001
From: jiangheng <jiangheng14@huawei.com>
Date: Fri, 27 Sep 2024 15:26:16 +0800
Subject: [PATCH] lwip: add pingpong mode support

---
 src/core/tcp.c                | 10 +++++++++-
 src/core/tcp_in.c             | 16 ++++++++++++++++
 src/core/tcp_out.c            | 14 +++++++++++++-
 src/include/lwip/tcp.h        |  7 +++++++
 src/include/lwipgz_tcp_priv.h | 19 ++++++++++++++++++-
 src/include/lwipopts.h        |  1 +
 6 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/src/core/tcp.c b/src/core/tcp.c
index c25f961..4a3c031 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -1702,8 +1702,13 @@ tcp_fasttmr_start:
     if (pcb->last_timer != tcp_timer_ctr) {
       struct tcp_pcb *next;
       pcb->last_timer = tcp_timer_ctr;
+#if !GAZELLE_TCP_PINGPONG_MODE
       /* send delayed ACKs */
       if (pcb->flags & TF_ACK_DELAY) {
+#else
+      if (!tcp_in_pingpong(pcb) || TIME_BEFORE(pcb->lrcvtime + TCP_ATO_MS, sys_now())) {
+        tcp_exit_pingpong(pcb);
+#endif
         LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
         MIB2_STATS_INC(mib2.tcpdelayackcnt);
         tcp_ack_now(pcb);
@@ -2154,6 +2159,10 @@ tcp_alloc(u8_t prio)
     pcb->client_rx_ring = NULL;
     pcb->client_tx_ring = NULL;
     pcb->free_ring = 0;
+#endif
+#if GAZELLE_TCP_PINGPONG_MODE
+    pcb->lrcvtime = 0;
+    pcb->pingpong = 0;
 #endif
     pcb_tci_init(pcb);
   }
@@ -2319,7 +2328,6 @@ tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
 }
 #endif /* LWIP_CALLBACK_API */
 
-
 /**
  * @ingroup tcp_raw
  * Specifies the polling interval and the callback function that should
diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c
index d9db957..1751561 100644
--- a/src/core/tcp_in.c
+++ b/src/core/tcp_in.c
@@ -1765,7 +1765,17 @@ tcp_receive(struct tcp_pcb *pcb)
 
 
         /* Acknowledge the segment(s). */
+#if GAZELLE_TCP_PINGPONG_MODE
+        if (tcp_in_pingpong(pcb)) {
+          tcp_clear_flags(pcb, TF_ACK_NOW);
+          tcp_set_flags(pcb, TF_ACK_DELAY);
+        } else {
+          tcp_ack(pcb);
+        }
+        pcb->lrcvtime = sys_now();
+#else
         tcp_ack(pcb);
+#endif
 
 #if LWIP_TCP_SACK_OUT
         if (LWIP_TCP_SACK_VALID(pcb, 0)) {
@@ -2012,12 +2022,18 @@ tcp_receive(struct tcp_pcb *pcb)
 #endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */
 #endif /* TCP_QUEUE_OOSEQ */
 
+#if GAZELLE_TCP_PINGONG_MODE
+        tcp_exit_pingpong(pcb); /* ooseq */
+#endif
         /* We send the ACK packet after we've (potentially) dealt with SACKs,
            so they can be included in the acknowledgment. */
         MIB2_STATS_INC(mib2.tcpinemptyacks);
         tcp_send_empty_ack(pcb);
       }
     } else {
+#if GAZELLE_TCP_PINGONG_MODE
+      tcp_exit_pingpong(pcb); /* out of window */
+#endif
       /* The incoming segment is not within the window. */
       MIB2_STATS_INC(mib2.tcpinemptyacks);
       tcp_send_empty_ack(pcb);
diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c
index 4cf1a62..1a55748 100644
--- a/src/core/tcp_out.c
+++ b/src/core/tcp_out.c
@@ -1499,6 +1499,9 @@ tcp_output(struct tcp_pcb *pcb)
     /* If the TF_ACK_NOW flag is set and the ->unsent queue is empty, construct
      * an empty ACK segment and send it. */
     if (pcb->flags & TF_ACK_NOW) {
+#if GAZELLE_TCP_PINGPONG_MODE
+      MIB2_STATS_INC(mib2.tcpinemptyacks);
+#endif
       return tcp_send_empty_ack(pcb);
     }
     /* nothing to send: shortcut out of here */
@@ -1546,6 +1549,9 @@ tcp_output(struct tcp_pcb *pcb)
     }
     /* We need an ACK, but can't send data now, so send an empty ACK */
     if (pcb->flags & TF_ACK_NOW) {
+#if GAZELLE_TCP_PINGPONG_MODE
+      MIB2_STATS_INC(mib2.tcpinemptyacks);
+#endif
       return tcp_send_empty_ack(pcb);
     }
     goto output_done;
@@ -1826,6 +1832,13 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif
   int seg_chksum_was_swapped = 0;
 #endif
 
+#if GAZELLE_TCP_PINGPONG_MODE
+  if (!tcp_in_pingpong(pcb)) {
+    if (TIME_BEFORE(sys_now(), pcb->lrcvtime + TCP_ATO_MS)) {
+      tcp_enter_pingpong(pcb);
+    }
+  }
+#endif
 #if GAZELLE_ENABLE
   lstack_calculate_aggregate(1, seg->len);
 #endif
@@ -2218,7 +2231,6 @@ tcp_rexmit(struct tcp_pcb *pcb)
   return ERR_OK;
 }
 
-
 /**
  * Handle retransmission after three dupacks received
  *
diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h
index 72fd166..a332e80 100644
--- a/src/include/lwip/tcp.h
+++ b/src/include/lwip/tcp.h
@@ -300,6 +300,13 @@ struct tcp_pcb {
   tcpwnd_size_t rcv_wnd;   /* receiver window available */
   tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */
   u32_t rcv_ann_right_edge; /* announced right edge of window */
+#if GAZELLE_TCP_PINGPONG_MODE
+#define TIME_BEFORE(t, compare_to) ((((u32_t)((t)-(compare_to))) > 0x7fffffff) ? 1 : 0)
+#define TCP_ATO_MS   200
+  u32_t lrcvtime;
+#define TCP_PINGPONG_THRESH  3
+  u8_t pingpong;
+#endif
 
 #if LWIP_TCP_SACK_OUT
   /* SACK ranges to include in ACK packets (entry is invalid if left==right) */
diff --git a/src/include/lwipgz_tcp_priv.h b/src/include/lwipgz_tcp_priv.h
index c6d0d00..e55eda2 100644
--- a/src/include/lwipgz_tcp_priv.h
+++ b/src/include/lwipgz_tcp_priv.h
@@ -207,6 +207,23 @@ static inline void vdev_unreg_done(const struct tcp_pcb *pcb)
     vdev_reg_done(REG_RING_TCP_CONNECT_CLOSE, pcb);
   }
 }
+
+#if GAZELLE_TCP_PINGPONG_MODE
+static inline bool tcp_in_pingpong(const struct tcp_pcb *pcb)
+{
+  return (pcb->pingpong >= TCP_PINGPONG_THRESH);
+}
+static inline void tcp_enter_pingpong(struct tcp_pcb *pcb)
+{
+  if (pcb->pingpong < TCP_PINGPONG_THRESH) {
+    pcb->pingpong++;
+  }
+}
+static inline void tcp_exit_pingpong(struct tcp_pcb *pcb)
+{
+  pcb->pingpong = 0;
+}
+#endif /* GAZELLE_TCP_PINGPONG_MODE */
 #endif /* GAZELLE_ENABLE */
 
-#endif /* __GAZELLE_TCP_PRIV_H__ */
\ No newline at end of file
+#endif /* __GAZELLE_TCP_PRIV_H__ */
diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h
index b32e372..c3ecb21 100644
--- a/src/include/lwipopts.h
+++ b/src/include/lwipopts.h
@@ -243,6 +243,7 @@
 
 #define GAZELLE_TCP_MAX_CONN_PER_THREAD 65535
 #define GAZELLE_TCP_REUSE_IPPORT 1
+#define GAZELLE_TCP_PINGPONG_MODE 1
 
 /*
    ------------------------------------
-- 
2.33.0

