aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Graham <dgraham@nortel.com>2009-07-29 12:05:57 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:55 -0400
commitaf87b823ca2b05257192e8d48dc686db6173d7b2 (patch)
treeda1756a3917bf1b737c4854bb7acc579c1c187d5
parentb4e8c6a7e6caa9c80edcbfb78fc50962b792d5f0 (diff)
sctp: Fix piggybacked ACKs
This patch corrects the conditions under which a SACK will be piggybacked on a DATA packet. The previous condition was incorrect due to a misinterpretation of RFC 4960 and/or RFC 2960. Specifically, the following paragraph from section 6.2 had not been implemented correctly: Before an endpoint transmits a DATA chunk, if any received DATA chunks have not been acknowledged (e.g., due to delayed ack), the sender should create a SACK and bundle it with the outbound DATA chunk, as long as the size of the final SCTP packet does not exceed the current MTU. See Section 6.2. When about to send a DATA chunk, the code now checks to see if the SACK timer is running. If it is, we know we have a SACK to send to the peer, so we append the SACK (assuming available space in the packet) and turn off the timer. For a simple request-response scenario, this will result in the SACK being bundled with the response, meaning the the SACK is received quickly by the client, and also meaning that no separate SACK packet needs to be sent by the server to acknowledge the request. Prior to this patch, a separate SACK packet would have been sent by the server SCTP only after its delayed-ACK timer had expired (usually 200ms). This is wasteful of bandwidth, and can also have a major negative impact on performance due the interaction of delayed ACKs with the Nagle algorithm. Signed-off-by: Doug Graham <dgraham@nortel.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
-rw-r--r--net/sctp/output.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/net/sctp/output.c b/net/sctp/output.c
index b94c21190566..94c110dcaf1d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -234,18 +234,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
234 if (sctp_chunk_is_data(chunk) && !pkt->has_sack && 234 if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
235 !pkt->has_cookie_echo) { 235 !pkt->has_cookie_echo) {
236 struct sctp_association *asoc; 236 struct sctp_association *asoc;
237 struct timer_list *timer;
237 asoc = pkt->transport->asoc; 238 asoc = pkt->transport->asoc;
239 timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
238 240
239 if (asoc->a_rwnd > asoc->rwnd) { 241 /* If the SACK timer is running, we have a pending SACK */
242 if (timer_pending(timer)) {
240 struct sctp_chunk *sack; 243 struct sctp_chunk *sack;
241 asoc->a_rwnd = asoc->rwnd; 244 asoc->a_rwnd = asoc->rwnd;
242 sack = sctp_make_sack(asoc); 245 sack = sctp_make_sack(asoc);
243 if (sack) { 246 if (sack) {
244 struct timer_list *timer;
245 retval = sctp_packet_append_chunk(pkt, sack); 247 retval = sctp_packet_append_chunk(pkt, sack);
246 asoc->peer.sack_needed = 0; 248 asoc->peer.sack_needed = 0;
247 timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; 249 if (del_timer(timer))
248 if (timer_pending(timer) && del_timer(timer))
249 sctp_association_put(asoc); 250 sctp_association_put(asoc);
250 } 251 }
251 } 252 }