Commit a93aba9b authored by Jon Grimm's avatar Jon Grimm

[SCTP] Control chunk bundling.

Control chunks should be bundled (implementor's guide advises
specifically of case were ERROR should be bundled with CE to avoid
race condition.   Patch introduces a outq_cork/outq_uncork to
immediate transferral of control chunks and then release to the
packet bundling code. 
parent 96a4ef02
...@@ -963,11 +963,14 @@ struct sctp_outq { ...@@ -963,11 +963,14 @@ struct sctp_outq {
/* How many unackd bytes do we have in-flight? */ /* How many unackd bytes do we have in-flight? */
__u32 outstanding_bytes; __u32 outstanding_bytes;
/* Corked? */
char cork;
/* Is this structure empty? */ /* Is this structure empty? */
int empty; char empty;
/* Are we kfree()able? */ /* Are we kfree()able? */
int malloced; char malloced;
}; };
struct sctp_outq *sctp_outq_new(struct sctp_association *); struct sctp_outq *sctp_outq_new(struct sctp_association *);
...@@ -985,10 +988,16 @@ int sctp_outq_set_output_handlers(struct sctp_outq *, ...@@ -985,10 +988,16 @@ int sctp_outq_set_output_handlers(struct sctp_outq *,
sctp_outq_ohandler_t build, sctp_outq_ohandler_t build,
sctp_outq_ohandler_force_t force); sctp_outq_ohandler_force_t force);
void sctp_outq_restart(struct sctp_outq *); void sctp_outq_restart(struct sctp_outq *);
void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
sctp_retransmit_reason_t); sctp_retransmit_reason_t);
void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
int sctp_outq_uncork(struct sctp_outq *);
/* Uncork and flush an outqueue. */
static inline void sctp_outq_cork(struct sctp_outq *q)
{
q->cork = 1;
}
/* These bind address data fields common between endpoints and associations */ /* These bind address data fields common between endpoints and associations */
struct sctp_bind_addr { struct sctp_bind_addr {
...@@ -1393,7 +1402,6 @@ struct sctp_association { ...@@ -1393,7 +1402,6 @@ struct sctp_association {
/* The largest timeout or RTO value to use in attempting an INIT */ /* The largest timeout or RTO value to use in attempting an INIT */
__u16 max_init_timeo; __u16 max_init_timeo;
int timeouts[SCTP_NUM_TIMEOUT_TYPES]; int timeouts[SCTP_NUM_TIMEOUT_TYPES];
struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES];
...@@ -1494,9 +1502,6 @@ struct sctp_association { ...@@ -1494,9 +1502,6 @@ struct sctp_association {
*/ */
struct sctp_ulpq ulpq; struct sctp_ulpq ulpq;
/* Need to send an ECNE Chunk? */
int need_ecne;
/* Last TSN that caused an ECNE Chunk to be sent. */ /* Last TSN that caused an ECNE Chunk to be sent. */
__u32 last_ecne_tsn; __u32 last_ecne_tsn;
...@@ -1509,9 +1514,6 @@ struct sctp_association { ...@@ -1509,9 +1514,6 @@ struct sctp_association {
/* Number of seconds of idle time before an association is closed. */ /* Number of seconds of idle time before an association is closed. */
__u32 autoclose; __u32 autoclose;
/* Name for debugging output... */
char *debug_name;
/* These are to support /* These are to support
* "SCTP Extensions for Dynamic Reconfiguration of IP Addresses * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses
* and Enforcement of Flow and Message Limits" * and Enforcement of Flow and Message Limits"
...@@ -1519,8 +1521,7 @@ struct sctp_association { ...@@ -1519,8 +1521,7 @@ struct sctp_association {
* or "ADDIP" for short. * or "ADDIP" for short.
*/ */
/* Is the ADDIP extension enabled for this association? */
int addip_enable;
/* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
* *
...@@ -1605,8 +1606,14 @@ struct sctp_association { ...@@ -1605,8 +1606,14 @@ struct sctp_association {
*/ */
__u32 addip_serial; __u32 addip_serial;
/* Is the ADDIP extension enabled for this association? */
char addip_enable;
/* Need to send an ECNE Chunk? */
char need_ecne;
/* Is it a temporary association? */ /* Is it a temporary association? */
__u8 temp; char temp;
}; };
......
...@@ -230,6 +230,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) ...@@ -230,6 +230,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
q->outstanding_bytes = 0; q->outstanding_bytes = 0;
q->empty = 1; q->empty = 1;
q->cork = 0;
q->malloced = 0; q->malloced = 0;
q->out_qlen = 0; q->out_qlen = 0;
...@@ -365,7 +366,8 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) ...@@ -365,7 +366,8 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
if (error < 0) if (error < 0)
return error; return error;
error = sctp_outq_flush(q, 0); if (!q->cork)
error = sctp_outq_flush(q, 0);
return error; return error;
} }
...@@ -816,8 +818,19 @@ struct sctp_chunk *sctp_fragment_chunk(struct sctp_chunk *chunk, ...@@ -816,8 +818,19 @@ struct sctp_chunk *sctp_fragment_chunk(struct sctp_chunk *chunk,
return NULL; return NULL;
} }
/* Cork the outqueue so queued chunks are really queued. */
int sctp_outq_uncork(struct sctp_outq *q)
{
int error = 0;
if (q->cork) {
q->cork = 0;
error = sctp_outq_flush(q, 0);
}
return error;
}
/* /*
* sctp_outq_flush - Try to flush an outqueue. * Try to flush an outqueue.
* *
* Description: Send everything in q which we legally can, subject to * Description: Send everything in q which we legally can, subject to
* congestion limitations. * congestion limitations.
......
...@@ -844,6 +844,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -844,6 +844,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
unsigned long timeout; unsigned long timeout;
struct sctp_transport *t; struct sctp_transport *t;
sctp_sackhdr_t sackh; sctp_sackhdr_t sackh;
int local_cork = 0;
if (SCTP_EVENT_T_TIMEOUT != event_type) if (SCTP_EVENT_T_TIMEOUT != event_type)
chunk = (struct sctp_chunk *) event_arg; chunk = (struct sctp_chunk *) event_arg;
...@@ -863,6 +864,10 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -863,6 +864,10 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_NEW_ASOC: case SCTP_CMD_NEW_ASOC:
/* Register a new association. */ /* Register a new association. */
if (local_cork) {
sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
}
asoc = cmd->obj.ptr; asoc = cmd->obj.ptr;
/* Register with the endpoint. */ /* Register with the endpoint. */
sctp_endpoint_add_asoc(ep, asoc); sctp_endpoint_add_asoc(ep, asoc);
...@@ -877,7 +882,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -877,7 +882,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_outq_teardown(&asoc->outqueue); sctp_outq_teardown(&asoc->outqueue);
break; break;
case SCTP_CMD_DELETE_TCB: case SCTP_CMD_DELETE_TCB:
if (local_cork) {
sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
}
/* Delete the current association. */ /* Delete the current association. */
sctp_cmd_delete_tcb(commands, asoc); sctp_cmd_delete_tcb(commands, asoc);
asoc = NULL; asoc = NULL;
...@@ -981,9 +990,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -981,9 +990,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
case SCTP_CMD_REPLY: case SCTP_CMD_REPLY:
/* If an caller has not already corked, do cork. */
if (!asoc->outqueue.cork) {
sctp_outq_cork(&asoc->outqueue);
local_cork = 1;
}
/* Send a chunk to our peer. */ /* Send a chunk to our peer. */
error = sctp_outq_tail(&asoc->outqueue, error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr);
cmd->obj.ptr);
break; break;
case SCTP_CMD_SEND_PKT: case SCTP_CMD_SEND_PKT:
...@@ -1001,7 +1014,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -1001,7 +1014,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_TRANSMIT: case SCTP_CMD_TRANSMIT:
/* Kick start transmission. */ /* Kick start transmission. */
error = sctp_outq_flush(&asoc->outqueue, 0); error = sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
break; break;
case SCTP_CMD_ECN_CE: case SCTP_CMD_ECN_CE:
...@@ -1172,13 +1186,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -1172,13 +1186,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
}; };
if (error) if (error)
return error; break;
} }
out:
if (local_cork)
sctp_outq_uncork(&asoc->outqueue);
return error; return error;
nomem: nomem:
error = -ENOMEM; error = -ENOMEM;
return error; goto out;
} }
...@@ -891,8 +891,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -891,8 +891,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
} }
if (asoc) { if (asoc) {
SCTP_DEBUG_PRINTK("Just looked up association: " SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc);
"%s. \n", asoc->debug_name);
/* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED /* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED
* socket that has an association in CLOSED state. This can * socket that has an association in CLOSED state. This can
...@@ -1092,6 +1091,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1092,6 +1091,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_primitive_SEND(asoc, chunk); sctp_primitive_SEND(asoc, chunk);
SCTP_DEBUG_PRINTK("We sent primitively.\n"); SCTP_DEBUG_PRINTK("We sent primitively.\n");
} }
sctp_datamsg_free(datamsg); sctp_datamsg_free(datamsg);
err = msg_len; err = msg_len;
......
...@@ -328,7 +328,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( ...@@ -328,7 +328,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
ch = (sctp_errhdr_t *)(chunk->skb->data); ch = (sctp_errhdr_t *)(chunk->skb->data);
cause = ch->cause; cause = ch->cause;
elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t);
/* Pull off the ERROR header. */ /* Pull off the ERROR header. */
skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); skb_pull(chunk->skb, sizeof(sctp_errhdr_t));
...@@ -336,10 +336,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( ...@@ -336,10 +336,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
/* Copy the skb to a new skb with room for us to prepend /* Copy the skb to a new skb with room for us to prepend
* notification with. * notification with.
*/ */
skb = skb_copy_expand(chunk->skb, skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error),
sizeof(struct sctp_remote_error), /* headroom */ 0, gfp);
0, /* tailroom */
gfp);
/* Pull off the rest of the cause TLV from the chunk. */ /* Pull off the rest of the cause TLV from the chunk. */
skb_pull(chunk->skb, elen); skb_pull(chunk->skb, elen);
......
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