Mercurial > illumos > illumos-gate
changeset 10037:d735c8ae153a
6621614 SCTP bundles partial data chunk
author | Nick Street <Nick.Street@Sun.COM> |
---|---|
date | Mon, 06 Jul 2009 06:01:37 -0700 |
parents | d1aae351293e |
children | aeed618cdc99 |
files | usr/src/uts/common/inet/sctp/sctp_impl.h usr/src/uts/common/inet/sctp/sctp_output.c |
diffstat | 2 files changed, 50 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h Mon Jul 06 04:04:07 2009 +0530 +++ b/usr/src/uts/common/inet/sctp/sctp_impl.h Mon Jul 06 06:01:37 2009 -0700 @@ -982,7 +982,6 @@ extern int sctp_build_hdrs(sctp_t *); extern int sctp_check_abandoned_msg(sctp_t *, mblk_t *); -extern void sctp_chunkify(sctp_t *, int, int); extern void sctp_clean_death(sctp_t *, int); extern void sctp_close_eager(sctp_t *); extern int sctp_compare_faddrsets(sctp_faddr_t *, sctp_faddr_t *);
--- a/usr/src/uts/common/inet/sctp/sctp_output.c Mon Jul 06 04:04:07 2009 +0530 +++ b/usr/src/uts/common/inet/sctp/sctp_output.c Mon Jul 06 06:01:37 2009 -0700 @@ -79,6 +79,7 @@ #include "sctp_impl.h" static struct kmem_cache *sctp_kmem_ftsn_set_cache; +static mblk_t *sctp_chunkify(sctp_t *, int, int, int); #ifdef DEBUG static boolean_t sctp_verify_chain(mblk_t *, mblk_t *); @@ -307,8 +308,16 @@ return (error); } -void -sctp_chunkify(sctp_t *sctp, int first_len, int bytes_to_send) +/* + * While there are messages on sctp_xmit_unsent, detach each one. For each: + * allocate space for the chunk header, fill in the data chunk, and fill in + * the chunk header. Then append it to sctp_xmit_tail. + * Return after appending as many bytes as required (bytes_to_send). + * We also return if we've appended one or more chunks, and find a subsequent + * unsent message is too big to fit in the segment. + */ +mblk_t * +sctp_chunkify(sctp_t *sctp, int mss, int firstseg_len, int bytes_to_send) { mblk_t *mp; mblk_t *chunk_mp; @@ -323,7 +332,12 @@ sctp_faddr_t *fp1; size_t xtralen; sctp_msg_hdr_t *msg_hdr; - sctp_stack_t *sctps = sctp->sctp_sctps; + sctp_stack_t *sctps = sctp->sctp_sctps; + sctp_msg_hdr_t *next_msg_hdr; + size_t nextlen; + int remaining_len = mss - firstseg_len; + + ASSERT(remaining_len >= 0); fp = SCTP_CHUNK_DEST(mdblk); if (fp == NULL) @@ -334,14 +348,23 @@ else xtralen = sctp->sctp_hdr6_len + sctps->sctps_wroff_xtra + sizeof (*sdc); - count = chunksize = first_len - sizeof (*sdc); + count = chunksize = remaining_len - sizeof (*sdc); nextmsg: + next_msg_hdr = (sctp_msg_hdr_t *)sctp->sctp_xmit_unsent->b_rptr; + nextlen = next_msg_hdr->smh_msglen; + /* + * Will the entire next message fit in the current packet ? + * if not, leave it on the unsent list. + */ + if ((firstseg_len != 0) && (nextlen > remaining_len)) + return (NULL); + chunk_mp = mdblk->b_cont; /* - * If this partially chunked, we ignore the first_len for now - * and use the one already present. For the unchunked bits, we - * use the length of the last chunk. + * If this partially chunked, we ignore the next one for now and + * use the one already present. For the unchunked bits, we use the + * length of the last chunk. */ if (SCTP_IS_MSG_CHUNKED(mdblk)) { int chunk_len; @@ -405,7 +428,7 @@ chunk_head->b_next = mdblk->b_cont; mdblk->b_cont = chunk_head; } - return; + return (sctp->sctp_xmit_tail); } if (chunk_tail != NULL) { chunk_tail->b_cont = split_mp; @@ -439,7 +462,7 @@ chunk_head->b_next = mdblk->b_cont; mdblk->b_cont = chunk_head; } - return; + return (sctp->sctp_xmit_tail); } chunk_hdr->b_rptr += xtralen - sizeof (*sdc); chunk_hdr->b_wptr = chunk_hdr->b_rptr + sizeof (*sdc); @@ -523,6 +546,7 @@ } goto nextmsg; } + return (sctp->sctp_xmit_tail); } void @@ -788,16 +812,17 @@ * skipped. A message can be abandoned if it has a non-zero timetolive and * transmission has not yet started or if it is a partially reliable * message and its time is up (assuming we are PR-SCTP aware). + * We only return a chunk if it will fit entirely in the current packet. * 'cansend' is used to determine if need to try and chunkify messages from * the unsent list, if any, and also as an input to sctp_chunkify() if so. * - * firstseg indicates the space already used, cansend represents remaining - * space in the window, ((sfa_pmss - firstseg) can therefore reasonably + * firstseg_len indicates the space already used, cansend represents remaining + * space in the window, ((sfa_pmss - firstseg_len) can therefore reasonably * be used to compute the cansend arg). */ mblk_t * sctp_get_msg_to_send(sctp_t *sctp, mblk_t **mp, mblk_t *meta, int *error, - int32_t firstseg, uint32_t cansend, sctp_faddr_t *fp) + int32_t firstseg_len, uint32_t cansend, sctp_faddr_t *fp) { mblk_t *mp1; sctp_msg_hdr_t *msg_hdr; @@ -903,8 +928,8 @@ goto chunk_done; } } - sctp_chunkify(sctp, fp->sfa_pmss - firstseg, cansend); - if ((meta = sctp->sctp_xmit_tail) == NULL) + meta = sctp_chunkify(sctp, fp->sfa_pmss, firstseg_len, cansend); + if (meta == NULL) goto chunk_done; /* * sctp_chunkify() won't advance sctp_xmit_tail if it adds @@ -1171,7 +1196,13 @@ goto unsent_data; } } - /* See if we can bundle more. */ + /* + * Bundle chunks. We linkb() the chunks together to send + * downstream in a single packet. + * Partial chunks MUST NOT be bundled with full chunks, so we + * rely on sctp_get_msg_to_send() to only return messages that + * will fit entirely in the current packet. + */ while (seglen < pathmax) { int32_t new_len; int32_t new_xtralen; @@ -1186,7 +1217,10 @@ meta->b_next, &error, seglen, (seglen - xtralen) >= cansend ? 0 : cansend - seglen, fp); - if (error != 0 || meta == NULL) + if (error != 0) + break; + /* If no more eligible chunks, cease bundling */ + if (meta == NULL) break; sctp->sctp_xmit_tail = meta; }