From 578c96e235937d8d769c00e656175734c3fcb5f5 Mon Sep 17 00:00:00 2001
From: yinbin <yinbin8@huawei.com>
Date: Tue, 10 Sep 2024 20:51:19 +0800
Subject: [PATCH] LWIPOPTS: support setsockopt SO_SNDBUF

---
 src/api/lwipgz_sock.c     | 30 ++++++++++++++++++++++++++++++
 src/api/sockets.c         | 16 ++++++++++++++++
 src/core/tcp.c            |  3 +++
 src/include/lwip/tcp.h    |  3 +++
 src/include/lwipgz_sock.h |  9 +++++++++
 src/include/lwipopts.h    |  4 ++++
 6 files changed, 65 insertions(+)

diff --git a/src/api/lwipgz_sock.c b/src/api/lwipgz_sock.c
index 5a5a5fd..96f54bc 100644
--- a/src/api/lwipgz_sock.c
+++ b/src/api/lwipgz_sock.c
@@ -154,3 +154,33 @@ void lwip_exit(void)
    */
   return;
 }
+
+#if GAZELLE_SO_SNDBUF
+void netconn_set_sndbufsize(struct netconn *conn, tcpwnd_size_t sndbufsize)
+{
+  struct tcp_pcb *tcp = conn->pcb.tcp;
+  
+  if (sndbufsize > TCP_SND_BUF_MAX) {
+    LWIP_DEBUGF(GAZELLE_DEBUG_WARNING,
+                ("netconn_set_sndbufsize: setting sndbufsize exceed TCP_SND_BUF_MAX. "
+                 "sndbufsize=%u, snd_buf_max=%u", sndbufsize, TCP_SND_BUF_MAX));
+    return;
+  }
+  if (sndbufsize >= tcp->snd_buf_max) {
+    tcp->snd_buf += sndbufsize - tcp->snd_buf_max;
+    tcp->snd_buf_max = sndbufsize;
+    return;
+  }
+  /* remaining snd_buf less than the mount to be reduced */
+  if (tcp->snd_buf < tcp->snd_buf_max - sndbufsize) {
+    LWIP_DEBUGF(GAZELLE_DEBUG_WARNING,
+                ("netconn_set_sndbufsize: setting sndbufsize too small. "
+                 "snd_buf available is %u, need reduce is %u\n", tcp->snd_buf,
+                 tcp->snd_buf_max - sndbufsize));
+    return;
+  }
+  tcp->snd_buf -= tcp->snd_buf_max - sndbufsize;
+  tcp->snd_buf_max = sndbufsize;
+  return;
+}
+#endif /* GAZELLE_SO_SNDBUF */
diff --git a/src/api/sockets.c b/src/api/sockets.c
index 3e64f66..7256c76 100644
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -3145,6 +3145,14 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
           LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
           break;
 #endif /* LWIP_SO_RCVTIMEO */
+#if GAZELLE_SO_SNDBUF
+        case SO_SNDBUF:
+          LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, tcpwnd_size_t);
+          if (netconn_type(sock->conn) == NETCONN_TCP) {
+            *(tcpwnd_size_t *)optval = netconn_get_sndbufsize(sock->conn);
+          }
+          break;
+#endif /* GAZELLE_SO_SNDBUF */ 
 #if LWIP_SO_RCVBUF
         case SO_RCVBUF:
           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
@@ -3546,6 +3554,14 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
           break;
         }
 #endif /* LWIP_SO_RCVTIMEO */
+#if GAZELLE_SO_SNDBUF
+        case SO_SNDBUF:
+          LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, tcpwnd_size_t);
+          if (netconn_type(sock->conn) == NETCONN_TCP) {
+            netconn_set_sndbufsize(sock->conn, *(const tcpwnd_size_t *)optval);    
+          }
+          break;
+#endif /* GAZELLE_SO_SNDBUF */
 #if LWIP_SO_RCVBUF
         case SO_RCVBUF:
           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
diff --git a/src/core/tcp.c b/src/core/tcp.c
index a35f19a..79e6310 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -2108,6 +2108,9 @@ tcp_alloc(u8_t prio)
     memset(pcb, 0, sizeof(struct tcp_pcb));
     pcb->prio = prio;
     pcb->snd_buf = TCP_SND_BUF;
+#if GAZELLE_SO_SNDBUF
+    pcb->snd_buf_max = TCP_SND_BUF;
+#endif /* GAZELLE_SO_SNDBUF */
     /* Start with a window that does not need scaling. When window scaling is
        enabled and used, the window is enlarged when both sides agree on scaling. */
     pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND);
diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h
index 9c8a2ca..72fd166 100644
--- a/src/include/lwip/tcp.h
+++ b/src/include/lwip/tcp.h
@@ -340,6 +340,9 @@ struct tcp_pcb {
   tcpwnd_size_t snd_wnd_max; /* the maximum sender window announced by the remote host */
 
   tcpwnd_size_t snd_buf;   /* Available buffer space for sending (in bytes). */
+#if GAZELLE_SO_SNDBUF
+  tcpwnd_size_t snd_buf_max; /* the max size of snd_buf */
+#endif /* GAZELLE_SO_SNDBUF */ 
 #define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
   u16_t snd_queuelen; /* Number of pbufs currently in the send buffer. */
 
diff --git a/src/include/lwipgz_sock.h b/src/include/lwipgz_sock.h
index e0fe7c8..4f8e17b 100644
--- a/src/include/lwipgz_sock.h
+++ b/src/include/lwipgz_sock.h
@@ -36,6 +36,10 @@
 #include "lwip/opt.h"
 #include "lwip/api.h"
 
+#if GAZELLE_SO_SNDBUF
+#include  "lwip/tcp.h"
+#endif /* GAZELLE_SO_SNDBUF */
+
 #if GAZELLE_ENABLE
 #include <semaphore.h>
 #include <rte_common.h>
@@ -193,4 +197,9 @@ struct lwip_sock {
 #endif /* GAZELLE_ENABLE */
 };
 
+#if GAZELLE_SO_SNDBUF
+void netconn_set_sndbufsize(struct netconn *conn, tcpwnd_size_t sndbufsize);
+#define netconn_get_sndbufsize(conn)                ((conn)->pcb.tcp->snd_buf_max)
+#endif /* GAZELLE_SO_SNDBUF */
+
 #endif /* __LWIPGZ_SOCK_H__ */
diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h
index 5cc7431..ea6588a 100644
--- a/src/include/lwipopts.h
+++ b/src/include/lwipopts.h
@@ -229,6 +229,8 @@
 
 #define TCP_SND_QUEUELEN (8191)
 
+#define TCP_SND_BUF_MAX (TCP_SND_QUEUELEN * TCP_MSS)
+
 #define TCP_SNDLOWAT (32768)
 
 #define TCP_SNDQUEUELOWAT (TCP_SND_QUEUELEN / 5)
@@ -265,6 +267,8 @@
 
 #define SO_REUSE_RXTOALL 1
 
+#define GAZELLE_SO_SNDBUF 1
+
 /*
    ------------------------------------
    --------- Debug log options --------
-- 
2.34.1

