diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-09-04 18:21:00 -0400 |
---|---|---|
committer | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-09-04 18:21:00 -0400 |
commit | 31b02e1549406efa346534acad956a42bc3f28c4 (patch) | |
tree | 3acc807275810eb2efdc5fc2744bdfc3528488c2 /net/sctp/outqueue.c | |
parent | f68b2e05f326971cd76c65aa91a1a41771dd7485 (diff) |
sctp: Failover transmitted list on transport delete
Add-IP feature allows users to delete an active transport. If that
transport has chunks in flight, those chunks need to be moved to another
transport or association may get into unrecoverable state.
Reported-by: Rafael Laufer <rlaufer@cisco.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r-- | net/sctp/outqueue.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index d765fc53e74d..c9f20e28521b 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -406,8 +406,9 @@ void sctp_retransmit_mark(struct sctp_outq *q, | |||
406 | * not be retransmitted | 406 | * not be retransmitted |
407 | */ | 407 | */ |
408 | if (!chunk->tsn_gap_acked) { | 408 | if (!chunk->tsn_gap_acked) { |
409 | chunk->transport->flight_size -= | 409 | if (chunk->transport) |
410 | sctp_data_size(chunk); | 410 | chunk->transport->flight_size -= |
411 | sctp_data_size(chunk); | ||
411 | q->outstanding_bytes -= sctp_data_size(chunk); | 412 | q->outstanding_bytes -= sctp_data_size(chunk); |
412 | q->asoc->peer.rwnd += (sctp_data_size(chunk) + | 413 | q->asoc->peer.rwnd += (sctp_data_size(chunk) + |
413 | sizeof(struct sk_buff)); | 414 | sizeof(struct sk_buff)); |
@@ -443,7 +444,8 @@ void sctp_retransmit_mark(struct sctp_outq *q, | |||
443 | q->asoc->peer.rwnd += (sctp_data_size(chunk) + | 444 | q->asoc->peer.rwnd += (sctp_data_size(chunk) + |
444 | sizeof(struct sk_buff)); | 445 | sizeof(struct sk_buff)); |
445 | q->outstanding_bytes -= sctp_data_size(chunk); | 446 | q->outstanding_bytes -= sctp_data_size(chunk); |
446 | transport->flight_size -= sctp_data_size(chunk); | 447 | if (chunk->transport) |
448 | transport->flight_size -= sctp_data_size(chunk); | ||
447 | 449 | ||
448 | /* sctpimpguide-05 Section 2.8.2 | 450 | /* sctpimpguide-05 Section 2.8.2 |
449 | * M5) If a T3-rtx timer expires, the | 451 | * M5) If a T3-rtx timer expires, the |
@@ -1310,6 +1312,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1310 | __u32 rtt; | 1312 | __u32 rtt; |
1311 | __u8 restart_timer = 0; | 1313 | __u8 restart_timer = 0; |
1312 | int bytes_acked = 0; | 1314 | int bytes_acked = 0; |
1315 | int migrate_bytes = 0; | ||
1313 | 1316 | ||
1314 | /* These state variables are for coherent debug output. --xguo */ | 1317 | /* These state variables are for coherent debug output. --xguo */ |
1315 | 1318 | ||
@@ -1343,8 +1346,9 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1343 | * considering it as 'outstanding'. | 1346 | * considering it as 'outstanding'. |
1344 | */ | 1347 | */ |
1345 | if (!tchunk->tsn_gap_acked) { | 1348 | if (!tchunk->tsn_gap_acked) { |
1346 | tchunk->transport->flight_size -= | 1349 | if (tchunk->transport) |
1347 | sctp_data_size(tchunk); | 1350 | tchunk->transport->flight_size -= |
1351 | sctp_data_size(tchunk); | ||
1348 | q->outstanding_bytes -= sctp_data_size(tchunk); | 1352 | q->outstanding_bytes -= sctp_data_size(tchunk); |
1349 | } | 1353 | } |
1350 | continue; | 1354 | continue; |
@@ -1378,6 +1382,20 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1378 | rtt); | 1382 | rtt); |
1379 | } | 1383 | } |
1380 | } | 1384 | } |
1385 | |||
1386 | /* If the chunk hasn't been marked as ACKED, | ||
1387 | * mark it and account bytes_acked if the | ||
1388 | * chunk had a valid transport (it will not | ||
1389 | * have a transport if ASCONF had deleted it | ||
1390 | * while DATA was outstanding). | ||
1391 | */ | ||
1392 | if (!tchunk->tsn_gap_acked) { | ||
1393 | tchunk->tsn_gap_acked = 1; | ||
1394 | bytes_acked += sctp_data_size(tchunk); | ||
1395 | if (!tchunk->transport) | ||
1396 | migrate_bytes += sctp_data_size(tchunk); | ||
1397 | } | ||
1398 | |||
1381 | if (TSN_lte(tsn, sack_ctsn)) { | 1399 | if (TSN_lte(tsn, sack_ctsn)) { |
1382 | /* RFC 2960 6.3.2 Retransmission Timer Rules | 1400 | /* RFC 2960 6.3.2 Retransmission Timer Rules |
1383 | * | 1401 | * |
@@ -1391,8 +1409,6 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1391 | restart_timer = 1; | 1409 | restart_timer = 1; |
1392 | 1410 | ||
1393 | if (!tchunk->tsn_gap_acked) { | 1411 | if (!tchunk->tsn_gap_acked) { |
1394 | tchunk->tsn_gap_acked = 1; | ||
1395 | bytes_acked += sctp_data_size(tchunk); | ||
1396 | /* | 1412 | /* |
1397 | * SFR-CACC algorithm: | 1413 | * SFR-CACC algorithm: |
1398 | * 2) If the SACK contains gap acks | 1414 | * 2) If the SACK contains gap acks |
@@ -1432,10 +1448,6 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1432 | * older than that newly acknowledged DATA | 1448 | * older than that newly acknowledged DATA |
1433 | * chunk, are qualified as 'Stray DATA chunks'. | 1449 | * chunk, are qualified as 'Stray DATA chunks'. |
1434 | */ | 1450 | */ |
1435 | if (!tchunk->tsn_gap_acked) { | ||
1436 | tchunk->tsn_gap_acked = 1; | ||
1437 | bytes_acked += sctp_data_size(tchunk); | ||
1438 | } | ||
1439 | list_add_tail(lchunk, &tlist); | 1451 | list_add_tail(lchunk, &tlist); |
1440 | } | 1452 | } |
1441 | 1453 | ||
@@ -1491,7 +1503,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1491 | tsn); | 1503 | tsn); |
1492 | tchunk->tsn_gap_acked = 0; | 1504 | tchunk->tsn_gap_acked = 0; |
1493 | 1505 | ||
1494 | bytes_acked -= sctp_data_size(tchunk); | 1506 | if (tchunk->transport) |
1507 | bytes_acked -= sctp_data_size(tchunk); | ||
1495 | 1508 | ||
1496 | /* RFC 2960 6.3.2 Retransmission Timer Rules | 1509 | /* RFC 2960 6.3.2 Retransmission Timer Rules |
1497 | * | 1510 | * |
@@ -1561,6 +1574,14 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1561 | #endif /* SCTP_DEBUG */ | 1574 | #endif /* SCTP_DEBUG */ |
1562 | if (transport) { | 1575 | if (transport) { |
1563 | if (bytes_acked) { | 1576 | if (bytes_acked) { |
1577 | /* We may have counted DATA that was migrated | ||
1578 | * to this transport due to DEL-IP operation. | ||
1579 | * Subtract those bytes, since the were never | ||
1580 | * send on this transport and shouldn't be | ||
1581 | * credited to this transport. | ||
1582 | */ | ||
1583 | bytes_acked -= migrate_bytes; | ||
1584 | |||
1564 | /* 8.2. When an outstanding TSN is acknowledged, | 1585 | /* 8.2. When an outstanding TSN is acknowledged, |
1565 | * the endpoint shall clear the error counter of | 1586 | * the endpoint shall clear the error counter of |
1566 | * the destination transport address to which the | 1587 | * the destination transport address to which the |
@@ -1589,7 +1610,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1589 | transport->flight_size -= bytes_acked; | 1610 | transport->flight_size -= bytes_acked; |
1590 | if (transport->flight_size == 0) | 1611 | if (transport->flight_size == 0) |
1591 | transport->partial_bytes_acked = 0; | 1612 | transport->partial_bytes_acked = 0; |
1592 | q->outstanding_bytes -= bytes_acked; | 1613 | q->outstanding_bytes -= bytes_acked + migrate_bytes; |
1593 | } else { | 1614 | } else { |
1594 | /* RFC 2960 6.1, sctpimpguide-06 2.15.2 | 1615 | /* RFC 2960 6.1, sctpimpguide-06 2.15.2 |
1595 | * When a sender is doing zero window probing, it | 1616 | * When a sender is doing zero window probing, it |