Commit 9c5c62be authored by Vlad Yasevich's avatar Vlad Yasevich

sctp: Send user messages to the lower layer as one

Currenlty, sctp breaks up user messages into fragments and
sends each fragment to the lower layer by itself.  This means
that for each fragment we go all the way down the stack
and back up.  This also discourages bundling of multiple
fragments when they can fit into a sigle packet (ex: due
to user setting a low fragmentation threashold).

We introduce a new command SCTP_CMD_SND_MSG and hand the
whole message down state machine.  The state machine and
the side-effect parser will cork the queue, add all chunks
from the message to the queue, and then un-cork the queue
thus causing the chunks to get transmitted.
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
parent 5d7ff261
...@@ -106,6 +106,7 @@ typedef enum { ...@@ -106,6 +106,7 @@ typedef enum {
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */ SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */ SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
SCTP_CMD_SEND_MSG, /* Send the whole use message */
SCTP_CMD_LAST SCTP_CMD_LAST
} sctp_verb_t; } sctp_verb_t;
...@@ -139,6 +140,7 @@ typedef union { ...@@ -139,6 +140,7 @@ typedef union {
struct sctp_ulpevent *ulpevent; struct sctp_ulpevent *ulpevent;
struct sctp_packet *packet; struct sctp_packet *packet;
sctp_sackhdr_t *sackh; sctp_sackhdr_t *sackh;
struct sctp_datamsg *msg;
} sctp_arg_t; } sctp_arg_t;
/* We are simulating ML type constructors here. /* We are simulating ML type constructors here.
...@@ -188,6 +190,7 @@ SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) ...@@ -188,6 +190,7 @@ SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init)
SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent) SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent)
SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet) SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet)
SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh)
SCTP_ARG_CONSTRUCTOR(DATAMSG, struct sctp_datamsg *, msg)
typedef struct { typedef struct {
sctp_arg_t obj; sctp_arg_t obj;
......
...@@ -643,6 +643,7 @@ struct sctp_datamsg { ...@@ -643,6 +643,7 @@ struct sctp_datamsg {
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
struct sctp_sndrcvinfo *, struct sctp_sndrcvinfo *,
struct msghdr *, int len); struct msghdr *, int len);
void sctp_datamsg_free(struct sctp_datamsg *);
void sctp_datamsg_put(struct sctp_datamsg *); void sctp_datamsg_put(struct sctp_datamsg *);
void sctp_chunk_fail(struct sctp_chunk *, int error); void sctp_chunk_fail(struct sctp_chunk *, int error);
int sctp_chunk_abandoned(struct sctp_chunk *); int sctp_chunk_abandoned(struct sctp_chunk *);
......
...@@ -73,6 +73,19 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp) ...@@ -73,6 +73,19 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
return msg; return msg;
} }
void sctp_datamsg_free(struct sctp_datamsg *msg)
{
struct sctp_chunk *chunk;
/* This doesn't have to be a _safe vairant because
* sctp_chunk_free() only drops the refs.
*/
list_for_each_entry(chunk, &msg->chunks, frag_list)
sctp_chunk_free(chunk);
sctp_datamsg_put(msg);
}
/* Final destructruction of datamsg memory. */ /* Final destructruction of datamsg memory. */
static void sctp_datamsg_destroy(struct sctp_datamsg *msg) static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
{ {
......
...@@ -931,6 +931,27 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc, ...@@ -931,6 +931,27 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc,
} }
/* Send the whole message, chunk by chunk, to the outqueue.
* This way the whole message is queued up and bundling if
* encouraged for small fragments.
*/
static int sctp_cmd_send_msg(struct sctp_association *asoc,
struct sctp_datamsg *msg)
{
struct sctp_chunk *chunk;
int error = 0;
list_for_each_entry(chunk, &msg->chunks, frag_list) {
error = sctp_outq_tail(&asoc->outqueue, chunk);
if (error)
break;
}
return error;
}
/* These three macros allow us to pull the debugging code out of the /* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real * main flow of sctp_do_sm() to keep attention focused on the real
* functionality there. * functionality there.
...@@ -1575,7 +1596,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1575,7 +1596,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_UPDATE_INITTAG: case SCTP_CMD_UPDATE_INITTAG:
asoc->peer.i.init_tag = cmd->obj.u32; asoc->peer.i.init_tag = cmd->obj.u32;
break; break;
case SCTP_CMD_SEND_MSG:
if (!asoc->outqueue.cork) {
sctp_outq_cork(&asoc->outqueue);
local_cork = 1;
}
error = sctp_cmd_send_msg(asoc, cmd->obj.msg);
break;
default: default:
printk(KERN_WARNING "Impossible command: %u, %p\n", printk(KERN_WARNING "Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr); cmd->verb, cmd->obj.ptr);
......
...@@ -4555,9 +4555,9 @@ sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep, ...@@ -4555,9 +4555,9 @@ sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_chunk *chunk = arg; struct sctp_datamsg *msg = arg;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); sctp_add_cmd_sf(commands, SCTP_CMD_SEND_MSG, SCTP_DATAMSG(msg));
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
......
...@@ -1814,20 +1814,22 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1814,20 +1814,22 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_set_owner_w(chunk); sctp_set_owner_w(chunk);
chunk->transport = chunk_tp; chunk->transport = chunk_tp;
/* Send it to the lower layers. Note: all chunks
* must either fail or succeed. The lower layer
* works that way today. Keep it that way or this
* breaks.
*/
err = sctp_primitive_SEND(asoc, chunk);
/* Did the lower layer accept the chunk? */
if (err)
sctp_chunk_free(chunk);
SCTP_DEBUG_PRINTK("We sent primitively.\n");
} }
sctp_datamsg_put(datamsg); /* Send it to the lower layers. Note: all chunks
* must either fail or succeed. The lower layer
* works that way today. Keep it that way or this
* breaks.
*/
err = sctp_primitive_SEND(asoc, datamsg);
/* Did the lower layer accept the chunk? */
if (err)
sctp_datamsg_free(datamsg);
else
sctp_datamsg_put(datamsg);
SCTP_DEBUG_PRINTK("We sent primitively.\n");
if (err) if (err)
goto out_free; goto out_free;
else else
......
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