aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-08-10 13:51:03 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:57 -0400
commit9c5c62be2f794c7cee533d856f9f34c3cf21ff1b (patch)
treee81bcc703cedf4e667b91504b5cf9e8e01ffb6a5
parent5d7ff261ef497c62f54c39effc259910a28b313d (diff)
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: Vlad Yasevich <vladislav.yasevich@hp.com>
-rw-r--r--include/net/sctp/command.h3
-rw-r--r--include/net/sctp/structs.h1
-rw-r--r--net/sctp/chunk.c13
-rw-r--r--net/sctp/sm_sideeffect.c29
-rw-r--r--net/sctp/sm_statefuns.c4
-rw-r--r--net/sctp/socket.c26
6 files changed, 61 insertions, 15 deletions
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
index 3b966802e05d..8be5135ff7aa 100644
--- a/include/net/sctp/command.h
+++ b/include/net/sctp/command.h
@@ -106,6 +106,7 @@ typedef enum {
106 SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */ 106 SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
107 SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ 107 SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
108 SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */ 108 SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
109 SCTP_CMD_SEND_MSG, /* Send the whole use message */
109 SCTP_CMD_LAST 110 SCTP_CMD_LAST
110} sctp_verb_t; 111} sctp_verb_t;
111 112
@@ -139,6 +140,7 @@ typedef union {
139 struct sctp_ulpevent *ulpevent; 140 struct sctp_ulpevent *ulpevent;
140 struct sctp_packet *packet; 141 struct sctp_packet *packet;
141 sctp_sackhdr_t *sackh; 142 sctp_sackhdr_t *sackh;
143 struct sctp_datamsg *msg;
142} sctp_arg_t; 144} sctp_arg_t;
143 145
144/* We are simulating ML type constructors here. 146/* We are simulating ML type constructors here.
@@ -188,6 +190,7 @@ SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init)
188SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent) 190SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent)
189SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet) 191SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet)
190SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) 192SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh)
193SCTP_ARG_CONSTRUCTOR(DATAMSG, struct sctp_datamsg *, msg)
191 194
192typedef struct { 195typedef struct {
193 sctp_arg_t obj; 196 sctp_arg_t obj;
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index edfcacf3250e..97024faaa08f 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -643,6 +643,7 @@ struct sctp_datamsg {
643struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, 643struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
644 struct sctp_sndrcvinfo *, 644 struct sctp_sndrcvinfo *,
645 struct msghdr *, int len); 645 struct msghdr *, int len);
646void sctp_datamsg_free(struct sctp_datamsg *);
646void sctp_datamsg_put(struct sctp_datamsg *); 647void sctp_datamsg_put(struct sctp_datamsg *);
647void sctp_chunk_fail(struct sctp_chunk *, int error); 648void sctp_chunk_fail(struct sctp_chunk *, int error);
648int sctp_chunk_abandoned(struct sctp_chunk *); 649int sctp_chunk_abandoned(struct sctp_chunk *);
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 7acaf15679b6..645577ddc33e 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -73,6 +73,19 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
73 return msg; 73 return msg;
74} 74}
75 75
76void sctp_datamsg_free(struct sctp_datamsg *msg)
77{
78 struct sctp_chunk *chunk;
79
80 /* This doesn't have to be a _safe vairant because
81 * sctp_chunk_free() only drops the refs.
82 */
83 list_for_each_entry(chunk, &msg->chunks, frag_list)
84 sctp_chunk_free(chunk);
85
86 sctp_datamsg_put(msg);
87}
88
76/* Final destructruction of datamsg memory. */ 89/* Final destructruction of datamsg memory. */
77static void sctp_datamsg_destroy(struct sctp_datamsg *msg) 90static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
78{ 91{
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 86426aac1600..238adf7978e9 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -931,6 +931,27 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc,
931 931
932} 932}
933 933
934/* Send the whole message, chunk by chunk, to the outqueue.
935 * This way the whole message is queued up and bundling if
936 * encouraged for small fragments.
937 */
938static int sctp_cmd_send_msg(struct sctp_association *asoc,
939 struct sctp_datamsg *msg)
940{
941 struct sctp_chunk *chunk;
942 int error = 0;
943
944 list_for_each_entry(chunk, &msg->chunks, frag_list) {
945 error = sctp_outq_tail(&asoc->outqueue, chunk);
946 if (error)
947 break;
948 }
949
950 return error;
951}
952
953
954
934/* These three macros allow us to pull the debugging code out of the 955/* These three macros allow us to pull the debugging code out of the
935 * main flow of sctp_do_sm() to keep attention focused on the real 956 * main flow of sctp_do_sm() to keep attention focused on the real
936 * functionality there. 957 * functionality there.
@@ -1575,7 +1596,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
1575 case SCTP_CMD_UPDATE_INITTAG: 1596 case SCTP_CMD_UPDATE_INITTAG:
1576 asoc->peer.i.init_tag = cmd->obj.u32; 1597 asoc->peer.i.init_tag = cmd->obj.u32;
1577 break; 1598 break;
1578 1599 case SCTP_CMD_SEND_MSG:
1600 if (!asoc->outqueue.cork) {
1601 sctp_outq_cork(&asoc->outqueue);
1602 local_cork = 1;
1603 }
1604 error = sctp_cmd_send_msg(asoc, cmd->obj.msg);
1605 break;
1579 default: 1606 default:
1580 printk(KERN_WARNING "Impossible command: %u, %p\n", 1607 printk(KERN_WARNING "Impossible command: %u, %p\n",
1581 cmd->verb, cmd->obj.ptr); 1608 cmd->verb, cmd->obj.ptr);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 50225dd2e6dc..910926906a3a 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -4555,9 +4555,9 @@ sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep,
4555 void *arg, 4555 void *arg,
4556 sctp_cmd_seq_t *commands) 4556 sctp_cmd_seq_t *commands)
4557{ 4557{
4558 struct sctp_chunk *chunk = arg; 4558 struct sctp_datamsg *msg = arg;
4559 4559
4560 sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); 4560 sctp_add_cmd_sf(commands, SCTP_CMD_SEND_MSG, SCTP_DATAMSG(msg));
4561 return SCTP_DISPOSITION_CONSUME; 4561 return SCTP_DISPOSITION_CONSUME;
4562} 4562}
4563 4563
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a7e544e3f28a..95a5623d79a0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1814,20 +1814,22 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
1814 sctp_set_owner_w(chunk); 1814 sctp_set_owner_w(chunk);
1815 1815
1816 chunk->transport = chunk_tp; 1816 chunk->transport = chunk_tp;
1817
1818 /* Send it to the lower layers. Note: all chunks
1819 * must either fail or succeed. The lower layer
1820 * works that way today. Keep it that way or this
1821 * breaks.
1822 */
1823 err = sctp_primitive_SEND(asoc, chunk);
1824 /* Did the lower layer accept the chunk? */
1825 if (err)
1826 sctp_chunk_free(chunk);
1827 SCTP_DEBUG_PRINTK("We sent primitively.\n");
1828 } 1817 }
1829 1818
1830 sctp_datamsg_put(datamsg); 1819 /* Send it to the lower layers. Note: all chunks
1820 * must either fail or succeed. The lower layer
1821 * works that way today. Keep it that way or this
1822 * breaks.
1823 */
1824 err = sctp_primitive_SEND(asoc, datamsg);
1825 /* Did the lower layer accept the chunk? */
1826 if (err)
1827 sctp_datamsg_free(datamsg);
1828 else
1829 sctp_datamsg_put(datamsg);
1830
1831 SCTP_DEBUG_PRINTK("We sent primitively.\n");
1832
1831 if (err) 1833 if (err)
1832 goto out_free; 1834 goto out_free;
1833 else 1835 else