Commit e83963b7 authored by Vlad Yasevich's avatar Vlad Yasevich

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: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
parent 3e62abf9
...@@ -61,8 +61,13 @@ ...@@ -61,8 +61,13 @@
#include <net/sctp/checksum.h> #include <net/sctp/checksum.h>
/* Forward declarations for private helpers. */ /* Forward declarations for private helpers. */
static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
struct sctp_chunk *chunk); struct sctp_chunk *chunk);
static void sctp_packet_append_data(struct sctp_packet *packet,
struct sctp_chunk *chunk);
static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet,
struct sctp_chunk *chunk,
u16 chunk_len);
/* Config a packet. /* Config a packet.
* This appears to be a followup set of initializations. * 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,13 +267,20 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
__u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
size_t psize;
size_t pmtu;
int too_big;
SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet,
chunk); chunk);
/* Data chunks are special. Before seeing what else we can
* bundle into this packet, check to see if we are allowed to
* send this DATA.
*/
if (sctp_chunk_is_data(chunk)) {
retval = sctp_packet_can_append_data(packet, chunk);
if (retval != SCTP_XMIT_OK)
goto finish;
}
/* Try to bundle AUTH chunk */ /* Try to bundle AUTH chunk */
retval = sctp_packet_bundle_auth(packet, chunk); retval = sctp_packet_bundle_auth(packet, chunk);
if (retval != SCTP_XMIT_OK) if (retval != SCTP_XMIT_OK)
...@@ -279,51 +291,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -279,51 +291,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
if (retval != SCTP_XMIT_OK) if (retval != SCTP_XMIT_OK)
goto finish; goto finish;
psize = packet->size; /* Check to see if this chunk will fit into the packet */
pmtu = ((packet->transport->asoc) ? retval = sctp_packet_will_fit(packet, chunk, chunk_len);
(packet->transport->asoc->pathmtu) : if (retval != SCTP_XMIT_OK)
(packet->transport->pathmtu)); goto finish;
too_big = (psize + chunk_len > pmtu);
/* Decide if we need to fragment or resubmit later. */
if (too_big) {
/* It's OK to fragmet at IP level if any one of the following
* is true:
* 1. The packet is empty (meaning this chunk is greater
* the MTU)
* 2. The chunk we are adding is a control chunk
* 3. The packet doesn't have any data in it yet and data
* requires authentication.
*/
if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
(!packet->has_data && chunk->auth)) {
/* We no longer do re-fragmentation.
* Just fragment at the IP layer, if we
* actually hit this condition
*/
packet->ipfragok = 1;
goto append;
} else {
retval = SCTP_XMIT_PMTU_FULL;
goto finish;
}
}
append:
/* We believe that this chunk is OK to add to the packet (as
* long as we have the cwnd for it).
*/
/* DATA is a special case since we must examine both rwnd and cwnd /* We believe that this chunk is OK to add to the packet */
* before we send DATA.
*/
switch (chunk->chunk_hdr->type) { switch (chunk->chunk_hdr->type) {
case SCTP_CID_DATA: case SCTP_CID_DATA:
retval = sctp_packet_append_data(packet, chunk); /* Account for the data being in the packet */
if (SCTP_XMIT_OK != retval) sctp_packet_append_data(packet, chunk);
goto finish;
/* Disallow SACK bundling after DATA. */ /* Disallow SACK bundling after DATA. */
packet->has_sack = 1; packet->has_sack = 1;
/* Disallow AUTH bundling after DATA */ /* Disallow AUTH bundling after DATA */
...@@ -633,16 +610,15 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -633,16 +610,15 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* 2nd Level Abstractions * 2nd Level Abstractions
********************************************************************/ ********************************************************************/
/* This private function handles the specifics of appending DATA chunks. */ /* This private function check to see if a chunk can be added */
static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
struct sctp_chunk *chunk) struct sctp_chunk *chunk)
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
size_t datasize, rwnd, inflight; size_t datasize, rwnd, inflight, flight_size;
struct sctp_transport *transport = packet->transport; struct sctp_transport *transport = packet->transport;
__u32 max_burst_bytes; __u32 max_burst_bytes;
struct sctp_association *asoc = transport->asoc; struct sctp_association *asoc = transport->asoc;
struct sctp_sock *sp = sctp_sk(asoc->base.sk);
struct sctp_outq *q = &asoc->outqueue; struct sctp_outq *q = &asoc->outqueue;
/* RFC 2960 6.1 Transmission of DATA Chunks /* 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,7 +635,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
*/ */
rwnd = asoc->peer.rwnd; rwnd = asoc->peer.rwnd;
inflight = asoc->outqueue.outstanding_bytes; inflight = q->outstanding_bytes;
flight_size = transport->flight_size;
datasize = sctp_data_size(chunk); datasize = sctp_data_size(chunk);
...@@ -682,8 +659,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -682,8 +659,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* cwnd = flightsize + Max.Burst * MTU * cwnd = flightsize + Max.Burst * MTU
*/ */
max_burst_bytes = asoc->max_burst * asoc->pathmtu; max_burst_bytes = asoc->max_burst * asoc->pathmtu;
if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { if ((flight_size + max_burst_bytes) < transport->cwnd) {
transport->cwnd = transport->flight_size + max_burst_bytes; transport->cwnd = flight_size + max_burst_bytes;
SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "
"transport: %p, cwnd: %d, " "transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, " "ssthresh: %d, flight_size: %d, "
...@@ -708,7 +685,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -708,7 +685,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* ignore the value of cwnd and SHOULD NOT delay retransmission. * ignore the value of cwnd and SHOULD NOT delay retransmission.
*/ */
if (chunk->fast_retransmit != SCTP_NEED_FRTX) if (chunk->fast_retransmit != SCTP_NEED_FRTX)
if (transport->flight_size >= transport->cwnd) { if (flight_size >= transport->cwnd) {
retval = SCTP_XMIT_RWND_FULL; retval = SCTP_XMIT_RWND_FULL;
goto finish; goto finish;
} }
...@@ -718,8 +695,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -718,8 +695,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* if any previously transmitted data on the connection remains * if any previously transmitted data on the connection remains
* unacknowledged. * unacknowledged.
*/ */
if (!sp->nodelay && sctp_packet_empty(packet) && if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) &&
q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { inflight && sctp_state(asoc, ESTABLISHED)) {
unsigned len = datasize + q->out_qlen; unsigned len = datasize + q->out_qlen;
/* Check whether this chunk and all the rest of pending /* 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,6 +709,19 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
} }
} }
finish:
return retval;
}
/* This private function does management things when adding DATA chunk */
static void sctp_packet_append_data(struct sctp_packet *packet,
struct sctp_chunk *chunk)
{
struct sctp_transport *transport = packet->transport;
size_t datasize = sctp_data_size(chunk);
struct sctp_association *asoc = transport->asoc;
u32 rwnd = asoc->peer.rwnd;
/* Keep track of how many bytes are in flight over this transport. */ /* Keep track of how many bytes are in flight over this transport. */
transport->flight_size += datasize; transport->flight_size += datasize;
...@@ -754,7 +744,45 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -754,7 +744,45 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
/* Has been accepted for transmission. */ /* Has been accepted for transmission. */
if (!asoc->peer.prsctp_capable) if (!asoc->peer.prsctp_capable)
chunk->msg->can_abandon = 0; chunk->msg->can_abandon = 0;
}
static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet,
struct sctp_chunk *chunk,
u16 chunk_len)
{
size_t psize;
size_t pmtu;
int too_big;
sctp_xmit_t retval = SCTP_XMIT_OK;
psize = packet->size;
pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pathmtu) :
(packet->transport->pathmtu));
too_big = (psize + chunk_len > pmtu);
/* Decide if we need to fragment or resubmit later. */
if (too_big) {
/* It's OK to fragmet at IP level if any one of the following
* is true:
* 1. The packet is empty (meaning this chunk is greater
* the MTU)
* 2. The chunk we are adding is a control chunk
* 3. The packet doesn't have any data in it yet and data
* requires authentication.
*/
if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
(!packet->has_data && chunk->auth)) {
/* We no longer do re-fragmentation.
* Just fragment at the IP layer, if we
* actually hit this condition
*/
packet->ipfragok = 1;
} else {
retval = SCTP_XMIT_PMTU_FULL;
}
}
finish:
return retval; return retval;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment