aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-08-07 10:43:07 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:56 -0400
commite83963b769a2c38b436f5dcf82309f5cbc2f6012 (patch)
tree682a21fa15fd49e22e11d4a64cfea6771b3b5d94 /net/sctp
parent3e62abf92f34d75fe22352d8d102e3cd2755804d (diff)
sctp: Generate SACKs when actually sending outbound DATA
We are now trying to bundle SACKs when we have outbound DATA to send. However, there are situations where this outbound DATA will not be sent (due to congestion or available window). In such cases it's ok to wait for the timer to expire. This patch refactors the sending code so that betfore attempting to bundle the SACK we check to see if the DATA will actually be transmitted. Based on eirlier works for Doug Graham <dgraham@nortel.com> and Wei Youngjun <yjwei@cn.fujitsu.com>. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/output.c142
1 files changed, 85 insertions, 57 deletions
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 94c110dcaf1d..e25e2e20b63d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -61,8 +61,13 @@
61#include <net/sctp/checksum.h> 61#include <net/sctp/checksum.h>
62 62
63/* Forward declarations for private helpers. */ 63/* Forward declarations for private helpers. */
64static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, 64static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
65 struct sctp_chunk *chunk); 65 struct sctp_chunk *chunk);
66static void sctp_packet_append_data(struct sctp_packet *packet,
67 struct sctp_chunk *chunk);
68static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet,
69 struct sctp_chunk *chunk,
70 u16 chunk_len);
66 71
67/* Config a packet. 72/* Config a packet.
68 * This appears to be a followup set of initializations. 73 * This appears to be a followup set of initializations.
@@ -262,13 +267,20 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
262{ 267{
263 sctp_xmit_t retval = SCTP_XMIT_OK; 268 sctp_xmit_t retval = SCTP_XMIT_OK;
264 __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); 269 __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
265 size_t psize;
266 size_t pmtu;
267 int too_big;
268 270
269 SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, 271 SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet,
270 chunk); 272 chunk);
271 273
274 /* Data chunks are special. Before seeing what else we can
275 * bundle into this packet, check to see if we are allowed to
276 * send this DATA.
277 */
278 if (sctp_chunk_is_data(chunk)) {
279 retval = sctp_packet_can_append_data(packet, chunk);
280 if (retval != SCTP_XMIT_OK)
281 goto finish;
282 }
283
272 /* Try to bundle AUTH chunk */ 284 /* Try to bundle AUTH chunk */
273 retval = sctp_packet_bundle_auth(packet, chunk); 285 retval = sctp_packet_bundle_auth(packet, chunk);
274 if (retval != SCTP_XMIT_OK) 286 if (retval != SCTP_XMIT_OK)
@@ -279,51 +291,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
279 if (retval != SCTP_XMIT_OK) 291 if (retval != SCTP_XMIT_OK)
280 goto finish; 292 goto finish;
281 293
282 psize = packet->size; 294 /* Check to see if this chunk will fit into the packet */
283 pmtu = ((packet->transport->asoc) ? 295 retval = sctp_packet_will_fit(packet, chunk, chunk_len);
284 (packet->transport->asoc->pathmtu) : 296 if (retval != SCTP_XMIT_OK)
285 (packet->transport->pathmtu)); 297 goto finish;
286
287 too_big = (psize + chunk_len > pmtu);
288
289 /* Decide if we need to fragment or resubmit later. */
290 if (too_big) {
291 /* It's OK to fragmet at IP level if any one of the following
292 * is true:
293 * 1. The packet is empty (meaning this chunk is greater
294 * the MTU)
295 * 2. The chunk we are adding is a control chunk
296 * 3. The packet doesn't have any data in it yet and data
297 * requires authentication.
298 */
299 if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
300 (!packet->has_data && chunk->auth)) {
301 /* We no longer do re-fragmentation.
302 * Just fragment at the IP layer, if we
303 * actually hit this condition
304 */
305 packet->ipfragok = 1;
306 goto append;
307
308 } else {
309 retval = SCTP_XMIT_PMTU_FULL;
310 goto finish;
311 }
312 }
313
314append:
315 /* We believe that this chunk is OK to add to the packet (as
316 * long as we have the cwnd for it).
317 */
318 298
319 /* DATA is a special case since we must examine both rwnd and cwnd 299 /* We believe that this chunk is OK to add to the packet */
320 * before we send DATA.
321 */
322 switch (chunk->chunk_hdr->type) { 300 switch (chunk->chunk_hdr->type) {
323 case SCTP_CID_DATA: 301 case SCTP_CID_DATA:
324 retval = sctp_packet_append_data(packet, chunk); 302 /* Account for the data being in the packet */
325 if (SCTP_XMIT_OK != retval) 303 sctp_packet_append_data(packet, chunk);
326 goto finish;
327 /* Disallow SACK bundling after DATA. */ 304 /* Disallow SACK bundling after DATA. */
328 packet->has_sack = 1; 305 packet->has_sack = 1;
329 /* Disallow AUTH bundling after DATA */ 306 /* Disallow AUTH bundling after DATA */
@@ -633,16 +610,15 @@ nomem:
633 * 2nd Level Abstractions 610 * 2nd Level Abstractions
634 ********************************************************************/ 611 ********************************************************************/
635 612
636/* This private function handles the specifics of appending DATA chunks. */ 613/* This private function check to see if a chunk can be added */
637static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, 614static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
638 struct sctp_chunk *chunk) 615 struct sctp_chunk *chunk)
639{ 616{
640 sctp_xmit_t retval = SCTP_XMIT_OK; 617 sctp_xmit_t retval = SCTP_XMIT_OK;
641 size_t datasize, rwnd, inflight; 618 size_t datasize, rwnd, inflight, flight_size;
642 struct sctp_transport *transport = packet->transport; 619 struct sctp_transport *transport = packet->transport;
643 __u32 max_burst_bytes; 620 __u32 max_burst_bytes;
644 struct sctp_association *asoc = transport->asoc; 621 struct sctp_association *asoc = transport->asoc;
645 struct sctp_sock *sp = sctp_sk(asoc->base.sk);
646 struct sctp_outq *q = &asoc->outqueue; 622 struct sctp_outq *q = &asoc->outqueue;
647 623
648 /* RFC 2960 6.1 Transmission of DATA Chunks 624 /* RFC 2960 6.1 Transmission of DATA Chunks
@@ -659,7 +635,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
659 */ 635 */
660 636
661 rwnd = asoc->peer.rwnd; 637 rwnd = asoc->peer.rwnd;
662 inflight = asoc->outqueue.outstanding_bytes; 638 inflight = q->outstanding_bytes;
639 flight_size = transport->flight_size;
663 640
664 datasize = sctp_data_size(chunk); 641 datasize = sctp_data_size(chunk);
665 642
@@ -682,8 +659,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
682 * cwnd = flightsize + Max.Burst * MTU 659 * cwnd = flightsize + Max.Burst * MTU
683 */ 660 */
684 max_burst_bytes = asoc->max_burst * asoc->pathmtu; 661 max_burst_bytes = asoc->max_burst * asoc->pathmtu;
685 if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { 662 if ((flight_size + max_burst_bytes) < transport->cwnd) {
686 transport->cwnd = transport->flight_size + max_burst_bytes; 663 transport->cwnd = flight_size + max_burst_bytes;
687 SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " 664 SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "
688 "transport: %p, cwnd: %d, " 665 "transport: %p, cwnd: %d, "
689 "ssthresh: %d, flight_size: %d, " 666 "ssthresh: %d, flight_size: %d, "
@@ -708,7 +685,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
708 * ignore the value of cwnd and SHOULD NOT delay retransmission. 685 * ignore the value of cwnd and SHOULD NOT delay retransmission.
709 */ 686 */
710 if (chunk->fast_retransmit != SCTP_NEED_FRTX) 687 if (chunk->fast_retransmit != SCTP_NEED_FRTX)
711 if (transport->flight_size >= transport->cwnd) { 688 if (flight_size >= transport->cwnd) {
712 retval = SCTP_XMIT_RWND_FULL; 689 retval = SCTP_XMIT_RWND_FULL;
713 goto finish; 690 goto finish;
714 } 691 }
@@ -718,8 +695,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
718 * if any previously transmitted data on the connection remains 695 * if any previously transmitted data on the connection remains
719 * unacknowledged. 696 * unacknowledged.
720 */ 697 */
721 if (!sp->nodelay && sctp_packet_empty(packet) && 698 if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) &&
722 q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { 699 inflight && sctp_state(asoc, ESTABLISHED)) {
723 unsigned len = datasize + q->out_qlen; 700 unsigned len = datasize + q->out_qlen;
724 701
725 /* Check whether this chunk and all the rest of pending 702 /* Check whether this chunk and all the rest of pending
@@ -732,6 +709,19 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
732 } 709 }
733 } 710 }
734 711
712finish:
713 return retval;
714}
715
716/* This private function does management things when adding DATA chunk */
717static void sctp_packet_append_data(struct sctp_packet *packet,
718 struct sctp_chunk *chunk)
719{
720 struct sctp_transport *transport = packet->transport;
721 size_t datasize = sctp_data_size(chunk);
722 struct sctp_association *asoc = transport->asoc;
723 u32 rwnd = asoc->peer.rwnd;
724
735 /* Keep track of how many bytes are in flight over this transport. */ 725 /* Keep track of how many bytes are in flight over this transport. */
736 transport->flight_size += datasize; 726 transport->flight_size += datasize;
737 727
@@ -754,7 +744,45 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
754 /* Has been accepted for transmission. */ 744 /* Has been accepted for transmission. */
755 if (!asoc->peer.prsctp_capable) 745 if (!asoc->peer.prsctp_capable)
756 chunk->msg->can_abandon = 0; 746 chunk->msg->can_abandon = 0;
747}
748
749static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet,
750 struct sctp_chunk *chunk,
751 u16 chunk_len)
752{
753 size_t psize;
754 size_t pmtu;
755 int too_big;
756 sctp_xmit_t retval = SCTP_XMIT_OK;
757
758 psize = packet->size;
759 pmtu = ((packet->transport->asoc) ?
760 (packet->transport->asoc->pathmtu) :
761 (packet->transport->pathmtu));
762
763 too_big = (psize + chunk_len > pmtu);
764
765 /* Decide if we need to fragment or resubmit later. */
766 if (too_big) {
767 /* It's OK to fragmet at IP level if any one of the following
768 * is true:
769 * 1. The packet is empty (meaning this chunk is greater
770 * the MTU)
771 * 2. The chunk we are adding is a control chunk
772 * 3. The packet doesn't have any data in it yet and data
773 * requires authentication.
774 */
775 if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
776 (!packet->has_data && chunk->auth)) {
777 /* We no longer do re-fragmentation.
778 * Just fragment at the IP layer, if we
779 * actually hit this condition
780 */
781 packet->ipfragok = 1;
782 } else {
783 retval = SCTP_XMIT_PMTU_FULL;
784 }
785 }
757 786
758finish:
759 return retval; 787 return retval;
760} 788}