From 08716b71ccb93c6d998d1654c1fac137f29d2851 Mon Sep 17 00:00:00 2001
From: wuchangsheng <wuchangsheng2@huawei.com>
Date: Tue, 13 Dec 2022 22:27:33 +0800
Subject: [PATCH] optimite pcb-list limit , send size and ack now

---
 src/core/tcp.c         |   1 +
 src/core/tcp_in.c      |  16 +++++++-
 src/core/tcp_out.c     | 103 ++++++++++++++++++++++++++++++-------------------
 src/include/lwip/opt.h |   2 +-
 src/include/lwip/tcp.h |   2 +
 src/include/lwipsock.h |   2 -
 6 files changed, 83 insertions(+), 43 deletions(-)

diff --git a/src/core/tcp.c b/src/core/tcp.c
index 51ada38..cb08f95 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -2297,6 +2297,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
     tcp_segs_free(pcb->unsent);
     tcp_segs_free(pcb->unacked);
     pcb->unacked = pcb->unsent = NULL;
+    pcb->last_unacked = pcb->last_unsent = NULL;
 #if TCP_OVERSIZE
     pcb->unsent_oversize = 0;
 #endif /* TCP_OVERSIZE */
diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c
index 2d6cb6a..78954bd 100644
--- a/src/core/tcp_in.c
+++ b/src/core/tcp_in.c
@@ -976,8 +976,14 @@ tcp_process(struct tcp_pcb *pcb)
           rseg = pcb->unsent;
           LWIP_ASSERT("no segment to free", rseg != NULL);
           pcb->unsent = rseg->next;
+          if (pcb->last_unsent == rseg) {
+            pcb->last_unsent = rseg->next;
+          }
         } else {
           pcb->unacked = rseg->next;
+          if (pcb->last_unacked == rseg) {
+            pcb->last_unacked = rseg->next;
+          }
         }
         tcp_seg_free(rseg);
 
@@ -1393,6 +1399,8 @@ tcp_receive(struct tcp_pcb *pcb)
       /* Remove segment from the unacknowledged list if the incoming
          ACK acknowledges them. */
       pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent);
+      if (pcb->unacked == NULL)
+        pcb->last_unacked = NULL;
       /* We go through the ->unsent list to see if any of the segments
          on the list are acknowledged by the ACK. This may seem
          strange since an "unsent" segment shouldn't be acked. The
@@ -1400,6 +1408,8 @@ tcp_receive(struct tcp_pcb *pcb)
          ->unsent list after a retransmission, so these segments may
          in fact have been sent once. */
       pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked);
+      if (pcb->unsent == NULL)
+        pcb->last_unsent = NULL;
 
       /* If there's nothing left to acknowledge, stop the retransmit
          timer, otherwise reset it to start again */
@@ -1736,7 +1746,11 @@ tcp_receive(struct tcp_pcb *pcb)
 
 
         /* Acknowledge the segment(s). */
-        tcp_ack(pcb);
+        if (flags & TCP_PSH) {
+            tcp_ack_now(pcb);
+        } else {
+            tcp_ack(pcb);
+        }
 
 #if LWIP_TCP_SACK_OUT
         if (LWIP_TCP_SACK_VALID(pcb, 0)) {
diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c
index f53750b..55053d8 100644
--- a/src/core/tcp_out.c
+++ b/src/core/tcp_out.c
@@ -631,11 +631,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
 #endif /* TCP_OVERSIZE */
   }
 #else /* USE_LIBOS */
-  if (pcb->unsent != NULL) {
-    /* @todo: this could be sped up by keeping last_unsent in the pcb */
-    for (last_unsent = pcb->unsent; last_unsent->next != NULL;
-         last_unsent = last_unsent->next);
-  }
+  last_unsent = pcb->last_unsent;
 #endif /* USE_LIBOS */
 
   /*
@@ -851,6 +847,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
    * Finally update the pcb state.
    */
 #if USE_LIBOS
+  if (queue) {
+    pcb->last_unsent = prev_seg;
+  }
   pcb->snd_lbb += pos;
   pcb->snd_buf -= pos;
 #else
@@ -1050,6 +1049,8 @@ tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split)
   /* Finally insert remainder into queue after split (which stays head) */
   seg->next = useg->next;
   useg->next = seg;
+  if (pcb->last_unsent == useg)
+    pcb->last_unsent = seg;
 
 #if TCP_OVERSIZE
   /* If remainder is last segment on the unsent, ensure we clear the oversize amount
@@ -1086,9 +1087,7 @@ tcp_send_fin(struct tcp_pcb *pcb)
 
   /* first, try to add the fin to the last unsent segment */
   if (pcb->unsent != NULL) {
-    struct tcp_seg *last_unsent;
-    for (last_unsent = pcb->unsent; last_unsent->next != NULL;
-         last_unsent = last_unsent->next);
+    struct tcp_seg *last_unsent = pcb->unsent;
 
     if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
       /* no SYN/FIN/RST flag in the header, we can add the FIN flag */
@@ -1182,10 +1181,10 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
   if (pcb->unsent == NULL) {
     pcb->unsent = seg;
   } else {
-    struct tcp_seg *useg;
-    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
+    struct tcp_seg *useg = pcb->last_unsent;
     useg->next = seg;
   }
+  pcb->last_unsent = seg;
 #if TCP_OVERSIZE
   /* The new unsent tail has no space */
   pcb->unsent_oversize = 0;
@@ -1314,6 +1313,7 @@ static struct tcp_seg *tcp_output_over(struct tcp_pcb *pcb, struct tcp_seg *seg,
     seg->next = NULL;
     if (useg == NULL) {
       pcb->unacked = seg;
+      pcb->last_unacked = seg;
       useg = seg;
     } else {
       if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) {
@@ -1329,6 +1329,7 @@ static struct tcp_seg *tcp_output_over(struct tcp_pcb *pcb, struct tcp_seg *seg,
         /* add segment to tail of unacked list */
         useg->next = seg;
         useg = seg;
+        pcb->last_unacked = seg;
       }
     }
   } else {
@@ -1460,15 +1461,14 @@ tcp_output(struct tcp_pcb *pcb)
   pcb->persist_backoff = 0;
 
   /* useg should point to last segment on unacked queue */
-  useg = pcb->unacked;
-  if (useg != NULL) {
-    for (; useg->next != NULL; useg = useg->next);
-  }
+  useg = pcb->last_unacked;
+
   /* data available and window allows it to be sent? */
 
+  u32_t send_len = 0;
 #if USE_LIBOS
   if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_TSO) {
-    while(seg) {
+    while(seg && send_len < 0xffff) {
       /**
        * 1）遍历unsent队列，找到所有的待发送seg. 将seg的buf串起来
        * 2) 生成新的seg, 调用tcp_output_segment, 新的seg释放掉
@@ -1510,6 +1510,7 @@ tcp_output(struct tcp_pcb *pcb)
           pre_pbuf->next = seg->p;
         }
 
+        send_len += seg->len;
         pre_pbuf = seg->p;
         next_seqno = seg_seqno + TCP_TCPLEN(seg);
         seg = seg->next;
@@ -1519,8 +1520,11 @@ tcp_output(struct tcp_pcb *pcb)
 
       if (first_pbuf == NULL) {
         err = tcp_output_seg(pcb, seg, netif, next_seqno + seg->len);
-        if (err != ERR_OK)
+        if (err != ERR_OK) {
+          if (pcb->unsent == NULL)
+            pcb->last_unsent = NULL;
           return err;
+        }
         pcb->unsent = seg->next;
         useg = tcp_output_over(pcb, seg, useg);
         seg = pcb->unsent;
@@ -1545,7 +1549,7 @@ tcp_output(struct tcp_pcb *pcb)
   } else
 #endif
 {
-  while (seg != NULL &&
+  while (seg != NULL && send_len < 0xffff &&
          lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
     LWIP_ASSERT("RST not expected here!",
                 (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
@@ -1560,6 +1564,7 @@ tcp_output(struct tcp_pcb *pcb)
         ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) {
       break;
     }
+    send_len += seg->len;
 #if TCP_CWND_DEBUG
     LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
                                  pcb->snd_wnd, pcb->cwnd, wnd,
@@ -1577,6 +1582,8 @@ tcp_output(struct tcp_pcb *pcb)
     if (err != ERR_OK) {
       /* segment could not be sent, for whatever reason */
       tcp_set_flags(pcb, TF_NAGLEMEMERR);
+      if (pcb->unsent == NULL)
+        pcb->last_unsent = NULL;
       return err;
     }
 #if TCP_OVERSIZE_DBGCHECK
@@ -1596,6 +1603,7 @@ tcp_output(struct tcp_pcb *pcb)
       /* unacked list is empty? */
       if (pcb->unacked == NULL) {
         pcb->unacked = seg;
+        pcb->last_unacked = seg;
         useg = seg;
         /* unacked list is not empty? */
       } else {
@@ -1615,6 +1623,7 @@ tcp_output(struct tcp_pcb *pcb)
           /* add segment to tail of unacked list */
           useg->next = seg;
           useg = useg->next;
+          pcb->last_unacked = seg;
         }
       }
       /* do not queue empty segments on the unacked list */
@@ -1632,6 +1641,8 @@ tcp_output(struct tcp_pcb *pcb)
 #endif /* TCP_OVERSIZE */
 
 output_done:
+  if (pcb->unsent == NULL)
+    pcb->last_unsent = NULL;
   tcp_clear_flags(pcb, TF_NAGLEMEMERR);
   return ERR_OK;
 }
@@ -1932,9 +1943,13 @@ tcp_rexmit_rto_prepare(struct tcp_pcb *pcb)
   }
 #endif /* TCP_OVERSIZE_DBGCHECK */
   /* unsent queue is the concatenated queue (of unacked, unsent) */
+  if (pcb->unsent == NULL) {
+    pcb->last_unsent = pcb->last_unacked;
+  }
   pcb->unsent = pcb->unacked;
   /* unacked queue is now empty */
   pcb->unacked = NULL;
+  pcb->last_unacked = NULL;
 
   /* Mark RTO in-progress */
   tcp_set_flags(pcb, TF_RTO);
@@ -2004,32 +2019,42 @@ tcp_rexmit(struct tcp_pcb *pcb)
   }
 
   seg = pcb->unacked;
+  while (seg) {
+    /* Give up if the segment is still referenced by the netif driver
+      due to deferred transmission. */
+    if (tcp_output_segment_busy(seg)) {
+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit busy\n"));
+      if (seg == pcb->unacked)
+        return ERR_VAL;
+      else
+        break;
+    }
 
-  /* Give up if the segment is still referenced by the netif driver
-     due to deferred transmission. */
-  if (tcp_output_segment_busy(seg)) {
-    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit busy\n"));
-    return ERR_VAL;
-  }
-
-  /* Move the first unacked segment to the unsent queue */
-  /* Keep the unsent queue sorted. */
-  pcb->unacked = seg->next;
+    /* Move the first unacked segment to the unsent queue */
+    /* Keep the unsent queue sorted. */
+    if (pcb->last_unacked == pcb->unacked)
+      pcb->last_unacked = pcb->unacked->next;
+    pcb->unacked = pcb->unacked->next;
 
-  cur_seg = &(pcb->unsent);
-  while (*cur_seg &&
-         TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) {
-    cur_seg = &((*cur_seg)->next );
-  }
-  seg->next = *cur_seg;
-  *cur_seg = seg;
+    cur_seg = &(pcb->unsent);
+    while (*cur_seg &&
+          TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) {
+      cur_seg = &((*cur_seg)->next);
+    }
+    if (*cur_seg == NULL)
+      pcb->last_unsent = seg;
+    seg->next = *cur_seg;
+    *cur_seg = seg;
 #if TCP_OVERSIZE
-  if (seg->next == NULL) {
-    /* the retransmitted segment is last in unsent, so reset unsent_oversize */
-    pcb->unsent_oversize = 0;
-  }
+    if (seg->next == NULL) {
+      /* the retransmitted segment is last in unsent, so reset unsent_oversize */
+      pcb->unsent_oversize = 0;
+    }
 #endif /* TCP_OVERSIZE */
 
+    seg = pcb->unacked;
+  }
+
   if (pcb->nrtx < 0xFF) {
     ++pcb->nrtx;
   }
@@ -2207,7 +2232,7 @@ tcp_output_control_segment(const struct tcp_pcb *pcb, struct pbuf *p,
       struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload;
 #if CHECKSUM_GEN_TCP_HW
     if (get_eth_params_tx_ol() & DEV_TX_OFFLOAD_TCP_CKSUM) {
-      tcph_cksum_set(p, TCP_HLEN);
+      tcph_cksum_set(p, TCPH_HDRLEN_BYTES(tcphdr));
       tcphdr->chksum = ip_chksum_pseudo_offload(IP_PROTO_TCP, p->tot_len, src, dst);
     } else {
       tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len,
diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h
index 8294cdd..83e7e93 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -1281,7 +1281,7 @@
  * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs).
  */
 #if !defined LWIP_TCP_SACK_OUT || defined __DOXYGEN__
-#define LWIP_TCP_SACK_OUT               0
+#define LWIP_TCP_SACK_OUT               1
 #endif
 
 /**
diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h
index b36bf33..b0ae02c 100644
--- a/src/include/lwip/tcp.h
+++ b/src/include/lwip/tcp.h
@@ -356,7 +356,9 @@ struct tcp_pcb {
 
   /* These are ordered by sequence number: */
   struct tcp_seg *unsent;   /* Unsent (queued) segments. */
+  struct tcp_seg *last_unsent;
   struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */
+  struct tcp_seg *last_unacked;
 #if TCP_QUEUE_OOSEQ
   struct tcp_seg *ooseq;    /* Received out of sequence segments. */
 #endif /* TCP_QUEUE_OOSEQ */
diff --git a/src/include/lwipsock.h b/src/include/lwipsock.h
index f919330..bf0d753 100644
--- a/src/include/lwipsock.h
+++ b/src/include/lwipsock.h
@@ -112,8 +112,6 @@ struct lwip_sock {
   struct list_node send_list;
   struct pbuf *send_lastdata;
   struct pbuf *send_pre_del;
-  uint64_t recv_all;
-  uint64_t send_all;
 
   char pad3 __rte_cache_aligned;
   /* nerver change */
-- 
2.8.4.windows.1

