Commit d6b6fece authored by Jon Grimm's avatar Jon Grimm

[SCTP] Bundle SACK with outgoing DATA.

If we are sending DATA, bundle a SACK.  Otherwise, we end up 
always waiting for the delayed SACK rules (timer or every other
packet rule) to kick in.   
parent c219cdce
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
*/ */
extern struct sctp_protocol sctp_proto; extern struct sctp_protocol sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); extern struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(struct sctp_protocol *, extern int sctp_copy_local_addr_list(struct sctp_protocol *,
struct sctp_bind_addr *, struct sctp_bind_addr *,
sctp_scope_t, int priority, int flags); sctp_scope_t, int priority, int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
...@@ -414,13 +414,22 @@ static inline __s32 sctp_jitter(__u32 rto) ...@@ -414,13 +414,22 @@ static inline __s32 sctp_jitter(__u32 rto)
sctp_rand ^= (sctp_rand << 12); sctp_rand ^= (sctp_rand << 12);
sctp_rand ^= (sctp_rand >> 20); sctp_rand ^= (sctp_rand >> 20);
/* Choose random number from 0 to rto, then move to -50% ~ +50% /* Choose random number from 0 to rto, then move to -50% ~ +50%
* of rto. * of rto.
*/ */
ret = sctp_rand % rto - (rto >> 1); ret = sctp_rand % rto - (rto >> 1);
return ret; return ret;
} }
/* Break down data chunks at this point. */
static inline int sctp_frag_point(int pmtu)
{
pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
pmtu -= sizeof(struct sctp_sack_chunk);
return pmtu;
}
/* Walk through a list of TLV parameters. Don't trust the /* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on * individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure * the chunk length to indicate when to stop. Make sure
......
...@@ -590,13 +590,16 @@ struct sctp_packet { ...@@ -590,13 +590,16 @@ struct sctp_packet {
/* This packet should advertise ECN capability to the network /* This packet should advertise ECN capability to the network
* via the ECT bit. * via the ECT bit.
*/ */
int ecn_capable; char ecn_capable;
/* This packet contains a COOKIE-ECHO chunk. */ /* This packet contains a COOKIE-ECHO chunk. */
int has_cookie_echo; char has_cookie_echo;
/* This packet containsa SACK chunk. */
char has_sack;
/* SCTP cannot fragment this packet. So let ip fragment it. */ /* SCTP cannot fragment this packet. So let ip fragment it. */
int ipfragok; char ipfragok;
int malloced; int malloced;
}; };
......
...@@ -421,8 +421,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -421,8 +421,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
"%d\n", asoc, asoc->pmtu); "%d\n", asoc, asoc->pmtu);
asoc->frag_point = asoc->pmtu; asoc->frag_point = sctp_frag_point(asoc->pmtu);
asoc->frag_point -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
/* The asoc->peer.port might not be meaningful yet, but /* The asoc->peer.port might not be meaningful yet, but
* initialize the packet structure anyway. * initialize the packet structure anyway.
...@@ -658,32 +657,21 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1, ...@@ -658,32 +657,21 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1,
} }
/* Return an ecne chunk to get prepended to a packet. /* Return an ecne chunk to get prepended to a packet.
* Note: We are sly and return a shared, prealloced chunk. * Note: We are sly and return a shared, prealloced chunk. FIXME:
* No we don't, but we could/should.
*/ */
sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc) sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc)
{ {
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
int need_ecne;
__u32 lowest_tsn;
/* Can be called from task or bh. Both need_ecne and /* Send ECNE if needed.
* last_ecne_tsn are written during bh. * Not being able to allocate a chunk here is not deadly.
*/ */
need_ecne = asoc->need_ecne; if (asoc->need_ecne)
lowest_tsn = asoc->last_ecne_tsn; chunk = sctp_make_ecne(asoc, asoc->last_ecne_tsn);
else
if (need_ecne) {
chunk = sctp_make_ecne(asoc, lowest_tsn);
/* ECNE is not mandatory to the flow. Being unable to
* alloc mem is not deadly. We are just unable to help
* out the network. If we run out of memory, just return
* NULL.
*/
} else {
chunk = NULL; chunk = NULL;
}
return chunk; return chunk;
} }
...@@ -986,8 +974,7 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc) ...@@ -986,8 +974,7 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
if (pmtu) { if (pmtu) {
asoc->pmtu = pmtu; asoc->pmtu = pmtu;
asoc->frag_point = pmtu - (SCTP_IP_OVERHEAD + asoc->frag_point = sctp_frag_point(pmtu);
sizeof(sctp_data_chunk_t));
} }
SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
......
...@@ -79,6 +79,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, ...@@ -79,6 +79,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
packet->ecn_capable = ecn_capable; packet->ecn_capable = ecn_capable;
packet->get_prepend_chunk = prepend_handler; packet->get_prepend_chunk = prepend_handler;
packet->has_cookie_echo = 0; packet->has_cookie_echo = 0;
packet->has_sack = 0;
packet->ipfragok = 0; packet->ipfragok = 0;
/* We might need to call the prepend_handler right away. */ /* We might need to call the prepend_handler right away. */
...@@ -100,6 +101,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, ...@@ -100,6 +101,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet->ecn_capable = 0; packet->ecn_capable = 0;
packet->get_prepend_chunk = NULL; packet->get_prepend_chunk = NULL;
packet->has_cookie_echo = 0; packet->has_cookie_echo = 0;
packet->has_sack = 0;
packet->ipfragok = 0; packet->ipfragok = 0;
packet->malloced = 0; packet->malloced = 0;
sctp_packet_reset(packet); sctp_packet_reset(packet);
...@@ -155,6 +157,37 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, ...@@ -155,6 +157,37 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
return retval; return retval;
} }
/* Try to bundle a SACK with the packet. */
static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
struct sctp_chunk *chunk)
{
sctp_xmit_t retval = SCTP_XMIT_OK;
/* If sending DATA and haven't aleady bundled a SACK, try to
* bundle one in to the packet.
*/
if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
!pkt->has_cookie_echo) {
struct sctp_association *asoc;
asoc = pkt->transport->asoc;
if (asoc->a_rwnd > asoc->rwnd) {
struct sctp_chunk *sack;
asoc->a_rwnd = asoc->rwnd;
sack = sctp_make_sack(asoc);
if (sack) {
struct timer_list *timer;
retval = sctp_packet_append_chunk(pkt, sack);
asoc->peer.sack_needed = 0;
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
if (timer_pending(timer) && del_timer(timer))
sctp_association_put(asoc);
}
}
}
return retval;
}
/* Append a chunk to the offered packet reporting back any inability to do /* Append a chunk to the offered packet reporting back any inability to do
* so. * so.
*/ */
...@@ -167,6 +200,10 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -167,6 +200,10 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
size_t pmtu; size_t pmtu;
int too_big; int too_big;
retval = sctp_packet_bundle_sack(packet, chunk);
if (retval != SCTP_XMIT_OK)
goto finish;
pmtu = ((packet->transport->asoc) ? pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pmtu) : (packet->transport->asoc->pmtu) :
(packet->transport->pmtu)); (packet->transport->pmtu));
...@@ -216,9 +253,10 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -216,9 +253,10 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
retval = sctp_packet_append_data(packet, chunk); retval = sctp_packet_append_data(packet, chunk);
if (SCTP_XMIT_OK != retval) if (SCTP_XMIT_OK != retval)
goto finish; goto finish;
} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) { } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
packet->has_cookie_echo = 1; packet->has_cookie_echo = 1;
} else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
packet->has_sack = 1;
/* It is OK to send this chunk. */ /* It is OK to send this chunk. */
__skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk); __skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
......
...@@ -876,7 +876,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -876,7 +876,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
start_timer = 0; start_timer = 0;
queue = &q->out; queue = &q->out;
while (NULL != (chunk = sctp_outq_dequeue_data(q))) { while (chunk = sctp_outq_dequeue_data(q)) {
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid /* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier. * stream identifier.
*/ */
...@@ -891,9 +891,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -891,9 +891,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
if (ev) if (ev)
sctp_ulpq_tail_event(&asoc->ulpq, ev); sctp_ulpq_tail_event(&asoc->ulpq, ev);
/* Free the chunk. This chunk is not on any /* Free the chunk. */
* list yet, just free it.
*/
sctp_free_chunk(chunk); sctp_free_chunk(chunk);
continue; continue;
} }
......
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