aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:59 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:59 -0400
commit4d3c46e6833208428d366630aa708f6876e61fc1 (patch)
treecb5f57a90a261b7443d202d96cf5725dbba371c8 /net
parent33ce828131ca6655b48bd2070dadd80f816dfe0d (diff)
sctp: drop a_rwnd to 0 when receive buffer overflows.
SCTP has a problem that when small chunks are used, it is possible to exhaust the receiver buffer without fully closing receive window. This happens due to all overhead that we have account for with small messages. To fix this, when receive buffer is exceeded, we'll drop the window to 0 and save the 'drop' portion. When application starts reading data and freeing up recevie buffer space, we'll wait until we've reached the 'drop' window and then add back this 'drop' one mtu at a time. This worked well in testing and under stress produced rather even recovery. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/associola.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 215b56951d76..39c3821b7d3d 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -202,6 +202,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
202 asoc->a_rwnd = asoc->rwnd; 202 asoc->a_rwnd = asoc->rwnd;
203 203
204 asoc->rwnd_over = 0; 204 asoc->rwnd_over = 0;
205 asoc->rwnd_press = 0;
205 206
206 /* Use my own max window until I learn something better. */ 207 /* Use my own max window until I learn something better. */
207 asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; 208 asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW;
@@ -1374,6 +1375,17 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
1374 asoc->rwnd += len; 1375 asoc->rwnd += len;
1375 } 1376 }
1376 1377
1378 /* If we had window pressure, start recovering it
1379 * once our rwnd had reached the accumulated pressure
1380 * threshold. The idea is to recover slowly, but up
1381 * to the initial advertised window.
1382 */
1383 if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) {
1384 int change = min(asoc->pathmtu, asoc->rwnd_press);
1385 asoc->rwnd += change;
1386 asoc->rwnd_press -= change;
1387 }
1388
1377 SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) " 1389 SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "
1378 "- %u\n", __func__, asoc, len, asoc->rwnd, 1390 "- %u\n", __func__, asoc, len, asoc->rwnd,
1379 asoc->rwnd_over, asoc->a_rwnd); 1391 asoc->rwnd_over, asoc->a_rwnd);
@@ -1406,17 +1418,38 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
1406/* Decrease asoc's rwnd by len. */ 1418/* Decrease asoc's rwnd by len. */
1407void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) 1419void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len)
1408{ 1420{
1421 int rx_count;
1422 int over = 0;
1423
1409 SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); 1424 SCTP_ASSERT(asoc->rwnd, "rwnd zero", return);
1410 SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); 1425 SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return);
1426
1427 if (asoc->ep->rcvbuf_policy)
1428 rx_count = atomic_read(&asoc->rmem_alloc);
1429 else
1430 rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
1431
1432 /* If we've reached or overflowed our receive buffer, announce
1433 * a 0 rwnd if rwnd would still be positive. Store the
1434 * the pottential pressure overflow so that the window can be restored
1435 * back to original value.
1436 */
1437 if (rx_count >= asoc->base.sk->sk_rcvbuf)
1438 over = 1;
1439
1411 if (asoc->rwnd >= len) { 1440 if (asoc->rwnd >= len) {
1412 asoc->rwnd -= len; 1441 asoc->rwnd -= len;
1442 if (over) {
1443 asoc->rwnd_press = asoc->rwnd;
1444 asoc->rwnd = 0;
1445 }
1413 } else { 1446 } else {
1414 asoc->rwnd_over = len - asoc->rwnd; 1447 asoc->rwnd_over = len - asoc->rwnd;
1415 asoc->rwnd = 0; 1448 asoc->rwnd = 0;
1416 } 1449 }
1417 SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n", 1450 SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u, %u)\n",
1418 __func__, asoc, len, asoc->rwnd, 1451 __func__, asoc, len, asoc->rwnd,
1419 asoc->rwnd_over); 1452 asoc->rwnd_over, asoc->rwnd_press);
1420} 1453}
1421 1454
1422/* Build the bind address list for the association based on info from the 1455/* Build the bind address list for the association based on info from the