net/tcp: fallback to unthrottle pool to avoid deadlock

Add a fallback mechanism to ensure that there are still available
iobs for an free connection, Guarantees all connections will have
a minimum threshold iob to keep the connection not be hanged.

Change-Id: I59bed98d135ccd1f16264b9ccacdd1b0d91261de
Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an
2020-11-27 09:50:38 +08:00
committed by Xiang Xiao
parent 4b6d117a93
commit bf21056001
5 changed files with 40 additions and 17 deletions
+1 -1
View File
@@ -256,7 +256,7 @@ static int sixlowpan_tcp_header(FAR struct tcp_conn_s *conn,
{ {
/* Update the TCP received window based on I/O buffer availability */ /* Update the TCP received window based on I/O buffer availability */
uint16_t recvwndo = tcp_get_recvwindow(dev); uint16_t recvwndo = tcp_get_recvwindow(dev, conn);
/* Set the TCP Window */ /* Set the TCP Window */
+4 -2
View File
@@ -1430,14 +1430,16 @@ int tcp_getsockopt(FAR struct socket *psock, int option,
* Calculate the TCP receive window for the specified device. * Calculate the TCP receive window for the specified device.
* *
* Input Parameters: * Input Parameters:
* dev - The device whose TCP receive window will be updated. * dev - The device whose TCP receive window will be updated.
* conn - The TCP connection structure holding connection information.
* *
* Returned Value: * Returned Value:
* The value of the TCP receive window to use. * The value of the TCP receive window to use.
* *
****************************************************************************/ ****************************************************************************/
uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev); uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *conn);
/**************************************************************************** /****************************************************************************
* Name: psock_tcp_cansend * Name: psock_tcp_cansend
+17 -4
View File
@@ -241,6 +241,7 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
uint16_t buflen) uint16_t buflen)
{ {
FAR struct iob_s *iob; FAR struct iob_s *iob;
bool throttled = true;
int ret; int ret;
/* Try to allocate on I/O buffer to start the chain without waiting (and /* Try to allocate on I/O buffer to start the chain without waiting (and
@@ -248,16 +249,28 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
* packet. * packet.
*/ */
iob = iob_tryalloc(true, IOBUSER_NET_TCP_READAHEAD); iob = iob_tryalloc(throttled, IOBUSER_NET_TCP_READAHEAD);
if (iob == NULL) if (iob == NULL)
{ {
nerr("ERROR: Failed to create new I/O buffer chain\n"); #if CONFIG_IOB_THROTTLE > 0
return 0; if (IOB_QEMPTY(&conn->readahead))
{
/* Fallback out of the throttled entry */
throttled = false;
iob = iob_tryalloc(throttled, IOBUSER_NET_TCP_READAHEAD);
}
#endif
if (iob == NULL)
{
nerr("ERROR: Failed to create new I/O buffer chain\n");
return 0;
}
} }
/* Copy the new appdata into the I/O buffer chain (without waiting) */ /* Copy the new appdata into the I/O buffer chain (without waiting) */
ret = iob_trycopyin(iob, buffer, buflen, 0, true, ret = iob_trycopyin(iob, buffer, buflen, 0, throttled,
IOBUSER_NET_TCP_READAHEAD); IOBUSER_NET_TCP_READAHEAD);
if (ret < 0) if (ret < 0)
{ {
+17 -9
View File
@@ -70,7 +70,8 @@
* *
****************************************************************************/ ****************************************************************************/
uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev) uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *conn)
{ {
uint16_t iplen; uint16_t iplen;
uint16_t mss; uint16_t mss;
@@ -139,9 +140,9 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
uint32_t rwnd; uint32_t rwnd;
/* The optimal TCP window size is the amount of TCP data that we can /* The optimal TCP window size is the amount of TCP data that we can
* currently buffer via TCP read-ahead buffering plus MSS for the * currently buffer via TCP read-ahead buffering for the device packet
* device packet buffer. This logic here assumes that all IOBs are * buffer. This logic here assumes that all IOBs are available for
* available for TCP buffering. * TCP buffering.
* *
* Assume that all of the available IOBs are can be used for buffering * Assume that all of the available IOBs are can be used for buffering
* on this connection. Also assume that at least one chain is available * on this connection. Also assume that at least one chain is available
@@ -154,7 +155,7 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
* buffering for this connection. * buffering for this connection.
*/ */
rwnd = (niob_avail * CONFIG_IOB_BUFSIZE) + mss; rwnd = (niob_avail * CONFIG_IOB_BUFSIZE);
if (rwnd > UINT16_MAX) if (rwnd > UINT16_MAX)
{ {
rwnd = UINT16_MAX; rwnd = UINT16_MAX;
@@ -164,17 +165,24 @@ uint16_t tcp_get_recvwindow(FAR struct net_driver_s *dev)
recvwndo = (uint16_t)rwnd; recvwndo = (uint16_t)rwnd;
} }
else if (IOB_QEMPTY(&conn->readahead))
{
/* Advertise maximum segment size for window edge if here is no
* available iobs on current "free" connection.
*/
recvwndo = mss;
}
else /* nqentry_avail == 0 || niob_avail == 0 */ else /* nqentry_avail == 0 || niob_avail == 0 */
{ {
/* No IOB chains or noIOBs are available. The only buffering /* No IOB chains or noIOBs are available.
* available is within the packet buffer itself. We can buffer no * Advertise the edge of window to zero.
* more than the MSS (unless we are very fast).
* *
* NOTE: If no IOBs are available, then the next packet will be * NOTE: If no IOBs are available, then the next packet will be
* lost if there is no listener on the connection. * lost if there is no listener on the connection.
*/ */
recvwndo = mss; recvwndo = 0;
} }
return recvwndo; return recvwndo;
+1 -1
View File
@@ -360,7 +360,7 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
{ {
/* Update the TCP received window based on I/O buffer availability */ /* Update the TCP received window based on I/O buffer availability */
uint16_t recvwndo = tcp_get_recvwindow(dev); uint16_t recvwndo = tcp_get_recvwindow(dev, conn);
/* Set the TCP Window */ /* Set the TCP Window */