diff options
author | Randall Stewart <rrs@FreeBSD.org> | 2007-04-15 11:58:26 +0000 |
---|---|---|
committer | Randall Stewart <rrs@FreeBSD.org> | 2007-04-15 11:58:26 +0000 |
commit | 478d3f0901c589952363a6fb122fd9b893358818 (patch) | |
tree | 66b3a65021698d30bae86cfd4452df34a0c14ca2 /sys/netinet/sctp_output.c | |
parent | a3859aa3860c9662bab4a958a5d3195e27f96d53 (diff) | |
download | src-test2-478d3f0901c589952363a6fb122fd9b893358818.tar.gz src-test2-478d3f0901c589952363a6fb122fd9b893358818.zip |
Notes
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r-- | sys/netinet/sctp_output.c | 390 |
1 files changed, 171 insertions, 219 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index e417d02221f4..e1ee546baccd 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3166,55 +3166,28 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, int how, int allonebuf, int type) { struct mbuf *m = NULL; - int aloc_size; - int index = 0; - int mbuf_threshold; - if (want_header) { - MGETHDR(m, how, type); - } else { - MGET(m, how, type); - } - if (m == NULL) { - return (NULL); - } - if (allonebuf == 0) - mbuf_threshold = sctp_mbuf_threshold_count; - else - mbuf_threshold = 1; - - - if (space_needed > (((mbuf_threshold - 1) * MLEN) + MHLEN)) { -try_again: - index = 4; - if (space_needed <= MCLBYTES) { - aloc_size = MCLBYTES; - } else if (space_needed <= MJUMPAGESIZE) { - aloc_size = MJUMPAGESIZE; - index = 5; - } else if (space_needed <= MJUM9BYTES) { - aloc_size = MJUM9BYTES; - index = 6; + m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); + if (allonebuf) { + int siz; + + if (SCTP_BUF_IS_EXTENDED(m)) { + siz = SCTP_BUF_EXTEND_SIZE(m); } else { - aloc_size = MJUM16BYTES; - index = 7; - } - m_cljget(m, how, aloc_size); - if (m == NULL) { - return (NULL); + if (want_header) + siz = MHLEN; + else + siz = MLEN; } - if (SCTP_BUF_IS_EXTENDED(m) == 0) { - if ((aloc_size != MCLBYTES) && - (allonebuf == 0)) { - aloc_size -= 10; - goto try_again; - } - sctp_m_freem(m); + if (siz < space_needed) { + m_freem(m); return (NULL); } } - SCTP_BUF_LEN(m) = 0; - SCTP_BUF_NEXT(m) = SCTP_BUF_NEXT_PKT(m) = NULL; + if (SCTP_BUF_NEXT(m)) { + sctp_m_freem(SCTP_BUF_NEXT(m)); + SCTP_BUF_NEXT(m) = NULL; + } #ifdef SCTP_MBUF_LOGGING if (SCTP_BUF_IS_EXTENDED(m)) { sctp_log_mb(m, SCTP_MBUF_IALLOC); @@ -5393,7 +5366,7 @@ sctp_msg_append(struct sctp_tcb *stcb, error = ECONNRESET; goto out_now; } - sp = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq, struct sctp_stream_queue_pending); + sctp_alloc_a_strmoq(stcb, sp); if (sp == NULL) { error = ENOMEM; goto out_now; @@ -5434,7 +5407,7 @@ sctp_msg_append(struct sctp_tcb *stcb, } SCTP_TCB_SEND_LOCK(stcb); sctp_snd_sb_alloc(stcb, sp->length); - stcb->asoc.stream_queue_cnt++; + atomic_add_int(&stcb->asoc.stream_queue_cnt, 1); TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); if ((srcv->sinfo_flags & SCTP_UNORDERED) == 0) { sp->strseq = strm->next_sequence_sent; @@ -6098,47 +6071,43 @@ sctp_can_we_split_this(struct sctp_tcb *stcb, { /* * Make a decision on if I should split a msg into multiple parts. + * This is only asked of incomplete messages. */ - if (goal_mtu < sctp_min_split_point) { - /* you don't want enough */ - return (0); - } - if ((sp->length <= goal_mtu) || ((sp->length - goal_mtu) < sctp_min_residual)) { - /* Sub-optimial residual don't split */ - return (0); - } - if (sp->msg_is_complete == 0) { - if (eeor_on) { - /* - * If we are doing EEOR we need to always send it if - * its the entire thing. + if (eeor_on) { + /* + * If we are doing EEOR we need to always send it if its the + * entire thing, since it might be all the guy is putting in + * the hopper. + */ + if (goal_mtu >= sp->length) { + /*- + * If we have data outstanding, + * we get another chance when the sack + * arrives to transmit - wait for more data + * + * Could this be optimized to be aware of + * two packets? + * */ - if (goal_mtu >= sp->length) + if (stcb->asoc.total_flight > 0) + return (0); + else return (sp->length); } else { - if (goal_mtu >= sp->length) { - /* - * If we cannot fill the amount needed there - * is no sense of splitting the chunk. - */ - return (0); - } + /* You can fill the rest */ + return (goal_mtu); } - /* - * If we reach here sp->length is larger than the goal_mtu. - * Do we wish to split it for the sake of packet putting - * together? - */ - if (goal_mtu >= min(sctp_min_split_point, stcb->asoc.smallest_mtu)) { - /* Its ok to split it */ - return (min(goal_mtu, frag_point)); - } - } else { - /* We can always split a complete message to make it fit */ - if (goal_mtu >= sp->length) - /* Take it all */ - return (sp->length); - + } + if ((sp->length <= goal_mtu) || ((sp->length - goal_mtu) < sctp_min_residual)) { + /* Sub-optimial residual don't split in non-eeor mode. */ + return (0); + } + /* + * If we reach here sp->length is larger than the goal_mtu. Do we + * wish to split it for the sake of packet putting together? + */ + if (goal_mtu >= min(sctp_min_split_point, frag_point)) { + /* Its ok to split it */ return (min(goal_mtu, frag_point)); } /* Nope, can't split */ @@ -6164,13 +6133,20 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, uint8_t rcv_flags = 0; uint8_t some_taken; uint8_t took_all = 0; + uint8_t send_lock_up = 0; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; +one_more_time: sp = TAILQ_FIRST(&strq->outqueue); if (sp == NULL) { *locked = 0; SCTP_TCB_SEND_LOCK(stcb); + sp = TAILQ_FIRST(&strq->outqueue); + if (sp) { + SCTP_TCB_SEND_UNLOCK(stcb); + goto one_more_time; + } if (strq->last_msg_incomplete) { printf("Huh? Stream:%d lm_in_c=%d but queue is NULL\n", strq->stream_no, strq->last_msg_incomplete); @@ -6179,16 +6155,52 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, SCTP_TCB_SEND_UNLOCK(stcb); return (0); } - SCTP_TCB_SEND_LOCK(stcb); - if ((sp->length == 0) && (sp->msg_is_complete == 0)) { - /* Must wait for more data, must be last msg */ - *locked = 1; - *giveup = 1; - SCTP_TCB_SEND_UNLOCK(stcb); - return (0); - } else if (sp->length == 0) { - /* This should not happen */ - panic("sp length is 0?"); + if (sp->msg_is_complete) { + if (sp->length == 0) { + if (sp->sender_all_done) { + /* + * We are doing deffered cleanup. Last time + * through when we took all the data the + * sender_all_done was not set. + */ + SCTP_TCB_SEND_LOCK(stcb); + send_lock_up = 1; + atomic_subtract_int(&asoc->stream_queue_cnt, 1); + TAILQ_REMOVE(&strq->outqueue, sp, next); + sctp_free_remote_addr(sp->net); + if (sp->data) { + sctp_m_freem(sp->data); + sp->data = NULL; + } + sctp_free_a_strmoq(stcb, sp); + + /* we can't be locked to it */ + *locked = 0; + stcb->asoc.locked_on_sending = NULL; + if (send_lock_up) { + SCTP_TCB_SEND_UNLOCK(stcb); + send_lock_up = 0; + } + /* back to get the next msg */ + goto one_more_time; + } else { + /* + * sender just finished this but still holds + * a reference + */ + *locked = 1; + *giveup = 1; + return (0); + } + } + } else { + /* is there some to get */ + if (sp->length == 0) { + /* no */ + *locked = 1; + *giveup = 1; + return (0); + } } some_taken = sp->some_taken; if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { @@ -6227,16 +6239,19 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, *locked = 1; } *giveup = 1; - SCTP_TCB_SEND_UNLOCK(stcb); return (0); } } - SCTP_TCB_SEND_UNLOCK(stcb); + /* If we reach here, we can copy out a chunk */ sctp_alloc_a_chunk(stcb, chk); if (chk == NULL) { /* No chunk memory */ out_gu: + if (send_lock_up) { + SCTP_TCB_SEND_UNLOCK(stcb); + send_lock_up = 0; + } *giveup = 1; return (0); } @@ -6250,12 +6265,19 @@ out_gu: /* clear out the chunk before setting up */ memset(chk, sizeof(*chk), 0); chk->rec.data.rcv_flags = rcv_flags; - SCTP_TCB_SEND_LOCK(stcb); if (SCTP_BUF_IS_EXTENDED(sp->data)) { chk->copy_by_ref = 1; } else { chk->copy_by_ref = 0; } + if ((sp->msg_is_complete == 0) && + (to_move >= sp->length)) { + SCTP_TCB_SEND_LOCK(stcb); + send_lock_up = 1; + } else { + send_lock_up = 0; + } + if (to_move >= sp->length) { /* we can steal the whole thing */ chk->data = sp->data; @@ -6271,7 +6293,6 @@ out_gu: if (chk->data == NULL) { sp->some_taken = some_taken; sctp_free_a_chunk(stcb, chk); - SCTP_TCB_SEND_UNLOCK(stcb); goto out_gu; } /* Pull off the data */ @@ -6283,6 +6304,7 @@ out_gu: SCTP_BUF_NEXT(m) = NULL; if (sp->tail_mbuf == m) { /* freeing tail */ + printf("Huh, freeing tail? - TSNH\n"); sp->tail_mbuf = sp->data; } sctp_m_free(m); @@ -6292,9 +6314,8 @@ out_gu: if (to_move > sp->length) { panic("Huh, how can to_move be larger?"); } else { - sp->length -= to_move; + atomic_subtract_int(&sp->length, to_move); } - if (M_LEADINGSPACE(chk->data) < sizeof(struct sctp_data_chunk)) { /* Not enough room for a chunk header, get some */ struct mbuf *m; @@ -6306,6 +6327,10 @@ out_gu: * all the data if there is no leading space, so we * must put the data back and restore. */ + if (send_lock_up == 0) { + SCTP_TCB_SEND_LOCK(stcb); + send_lock_up = 1; + } if (took_all) { /* unsteal the data */ sp->data = chk->data; @@ -6322,7 +6347,6 @@ out_gu: sp->length += to_move; chk->data = NULL; sctp_free_a_chunk(stcb, chk); - SCTP_TCB_SEND_UNLOCK(stcb); goto out_gu; } else { SCTP_BUF_LEN(m) = 0; @@ -6334,8 +6358,8 @@ out_gu: SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_DONTWAIT); if (chk->data == NULL) { /* HELP */ + printf("prepend fails HELP?\n"); sctp_free_a_chunk(stcb, chk); - SCTP_TCB_SEND_UNLOCK(stcb); goto out_gu; } sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk)); @@ -6423,9 +6447,13 @@ out_gu: if (sp->pr_sctp_on) { sctp_set_prsctp_policy(stcb, sp); } - if (sp->msg_is_complete && (sp->length == 0)) { + if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) { /* All done pull and kill the message */ - asoc->stream_queue_cnt--; + atomic_subtract_int(&asoc->stream_queue_cnt, 1); + if (send_lock_up == 0) { + SCTP_TCB_SEND_LOCK(stcb); + send_lock_up = 1; + } TAILQ_REMOVE(&strq->outqueue, sp, next); sctp_free_remote_addr(sp->net); if (sp->data) { @@ -6450,7 +6478,10 @@ out_gu: } TAILQ_INSERT_TAIL(&asoc->send_queue, chk, sctp_next); asoc->send_queue_cnt++; - SCTP_TCB_SEND_UNLOCK(stcb); + if (send_lock_up) { + SCTP_TCB_SEND_UNLOCK(stcb); + send_lock_up = 0; + } return (to_move); } @@ -7009,8 +7040,8 @@ again_one_more_time: no_fragmentflg, 0, NULL, asconf))) { if (error == ENOBUFS) { asoc->ifp_had_enobuf = 1; + SCTP_STAT_INCR(sctps_lowlevelerr); } - SCTP_STAT_INCR(sctps_lowlevelerr); if (from_where == 0) { SCTP_STAT_INCR(sctps_lowlevelerrusr); } @@ -7279,9 +7310,9 @@ again_one_more_time: asconf))) { /* error, we could not output */ if (error == ENOBUFS) { + SCTP_STAT_INCR(sctps_lowlevelerr); asoc->ifp_had_enobuf = 1; } - SCTP_STAT_INCR(sctps_lowlevelerr); if (from_where == 0) { SCTP_STAT_INCR(sctps_lowlevelerrusr); } @@ -10317,13 +10348,8 @@ sctp_copy_resume(struct sctp_stream_queue_pending *sp, uint32_t * sndout, struct mbuf **new_tail) { - -/*#if defined(__FreeBSD__) && __FreeBSD_version >= 602000*/ -#if defined(_NOT_YET_) - struct mbuf *m; -/* take out max_hdr */ m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0, (M_PKTHDR | (user_marks_eor ? M_EOR : 0))); if (m == NULL) @@ -10332,55 +10358,6 @@ sctp_copy_resume(struct sctp_stream_queue_pending *sp, *sndout = m_length(m, NULL); *new_tail = m_last(m); return (m); -#else - int left, cancpy, willcpy; - struct mbuf *m, *prev, *head; - - left = min(uio->uio_resid, max_send_len); - /* Always get a header just in case */ - head = sctp_get_mbuf_for_msg(left, 0, M_WAIT, 0, MT_DATA); - cancpy = M_TRAILINGSPACE(head); - willcpy = min(cancpy, left); - *error = uiomove(mtod(head, caddr_t), willcpy, uio); - if (*error) { - sctp_m_freem(head); - return (NULL); - } - *sndout += willcpy; - left -= willcpy; - SCTP_BUF_LEN(head) = willcpy; - m = head; - *new_tail = head; - while (left > 0) { - /* move in user data */ - SCTP_BUF_NEXT(m) = sctp_get_mbuf_for_msg(left, 0, M_WAIT, 0, MT_DATA); - if (SCTP_BUF_NEXT(m) == NULL) { - sctp_m_freem(head); - *new_tail = NULL; - *error = ENOMEM; - return (NULL); - } - prev = m; - m = SCTP_BUF_NEXT(m); - cancpy = M_TRAILINGSPACE(m); - willcpy = min(cancpy, left); - *error = uiomove(mtod(m, caddr_t), willcpy, uio); - if (*error) { - sctp_m_freem(head); - *new_tail = NULL; - *error = EFAULT; - return (NULL); - } - SCTP_BUF_LEN(m) = willcpy; - left -= willcpy; - *sndout += willcpy; - *new_tail = m; - if (left == 0) { - SCTP_BUF_NEXT(m) = NULL; - } - } - return (head); -#endif } static int @@ -10390,65 +10367,14 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, { int left; -/*#if defined(__FreeBSD__) && __FreeBSD_version >= 602000*/ -#if defined(_NOT_YET_) left = sp->length; - sp->data = m_uiotombuf(uio, M_WAITOK, 0, resv_upfront, M_PKTHDR); + sp->data = m_uiotombuf(uio, M_WAITOK, sp->length, + resv_upfront, M_PKTHDR); if (sp->data == NULL) return (ENOMEM); - sp->length = m_length(sp->data, NULL); - sp->tail_mbuf = m_last(sp->data); - return (0); -#else - int cancpy, willcpy, error; - struct mbuf *m, *head; - int cpsz = 0; - /* First one gets a header */ - left = sp->length; - head = m = sctp_get_mbuf_for_msg((left + resv_upfront), 0, M_WAIT, 0, MT_DATA); - if (m == NULL) { - return (ENOMEM); - } - /*- - * Add this one for m in now, that way if the alloc fails we won't - * have a bad cnt. - */ - SCTP_BUF_RESV_UF(m, resv_upfront); - cancpy = M_TRAILINGSPACE(m); - willcpy = min(cancpy, left); - while (left > 0) { - /* move in user data */ - error = uiomove(mtod(m, caddr_t), willcpy, uio); - if (error) { - sctp_m_freem(head); - return (error); - } - SCTP_BUF_LEN(m) = willcpy; - left -= willcpy; - cpsz += willcpy; - if (left > 0) { - SCTP_BUF_NEXT(m) = sctp_get_mbuf_for_msg(left, 0, M_WAIT, 0, MT_DATA); - if (SCTP_BUF_NEXT(m) == NULL) { - /* - * the head goes back to caller, he can free - * the rest - */ - sctp_m_freem(head); - return (ENOMEM); - } - m = SCTP_BUF_NEXT(m); - cancpy = M_TRAILINGSPACE(m); - willcpy = min(cancpy, left); - } else { - sp->tail_mbuf = m; - SCTP_BUF_NEXT(m) = NULL; - } - } - sp->data = head; - sp->length = cpsz; + sp->tail_mbuf = m_last(sp->data); return (0); -#endif } @@ -10491,13 +10417,14 @@ sctp_copy_it_in(struct sctp_tcb *stcb, *error = ECONNRESET; goto out_now; } - sp = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq, struct sctp_stream_queue_pending); + sctp_alloc_a_strmoq(stcb, sp); if (sp == NULL) { *error = ENOMEM; goto out_now; } SCTP_INCR_STRMOQ_COUNT(); sp->act_flags = 0; + sp->sender_all_done = 0; sp->sinfo_flags = srcv->sinfo_flags; sp->timetolive = srcv->sinfo_timetolive; sp->ppid = srcv->sinfo_ppid; @@ -10516,6 +10443,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb, } else { sp->msg_is_complete = 0; } + sp->sender_all_done = 0; sp->some_taken = 0; resv_in_first = sizeof(struct sctp_data_chunk); sp->data = sp->tail_mbuf = NULL; @@ -10541,6 +10469,8 @@ out_now: } + + int sctp_sosend(struct socket *so, struct sockaddr *addr, @@ -11122,6 +11052,11 @@ sctp_lower_sosend(struct socket *so, atomic_add_int(&stcb->total_sends, 1); if (top == NULL) { struct sctp_stream_queue_pending *sp; + +#ifdef INVARIANTS + struct sctp_stream_queue_pending *msp; + +#endif struct sctp_stream_out *strm; uint32_t sndout, initial_out; int user_marks_eor; @@ -11151,6 +11086,11 @@ sctp_lower_sosend(struct socket *so, goto out; } SCTP_TCB_SEND_LOCK(stcb); +#ifdef INVARIANTS + msp = TAILQ_LAST(&strm->outqueue, sctp_streamhead); + if (msp && (msp->msg_is_complete == 0)) + panic("Huh, new mesg and old not done?"); +#endif if (sp->msg_is_complete) { strm->last_msg_incomplete = 0; asoc->stream_locked = 0; @@ -11162,10 +11102,11 @@ sctp_lower_sosend(struct socket *so, strm->last_msg_incomplete = 1; asoc->stream_locked = 1; asoc->stream_locked_on = srcv->sinfo_stream; + sp->sender_all_done = 0; } sctp_snd_sb_alloc(stcb, sp->length); - asoc->stream_queue_cnt++; + atomic_add_int(&asoc->stream_queue_cnt, 1); TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); if ((srcv->sinfo_flags & SCTP_UNORDERED) == 0) { sp->strseq = strm->next_sequence_sent; @@ -11186,7 +11127,9 @@ sctp_lower_sosend(struct socket *so, } SCTP_TCB_SEND_UNLOCK(stcb); } else { + SCTP_TCB_SEND_LOCK(stcb); sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead); + SCTP_TCB_SEND_UNLOCK(stcb); if (sp == NULL) { /* ???? Huh ??? last msg is gone */ #ifdef INVARIANTS @@ -11233,6 +11176,7 @@ sctp_lower_sosend(struct socket *so, sctp_m_freem(mm); if (stcb->asoc.state & SCTP_PCB_FLAGS_WAS_ABORTED) error = ECONNRESET; + SCTP_TCB_SEND_UNLOCK(stcb); goto out; } if (sp->tail_mbuf) { @@ -11245,8 +11189,9 @@ sctp_lower_sosend(struct socket *so, sp->tail_mbuf = new_tail; } sctp_snd_sb_alloc(stcb, sndout); - sp->length += sndout; + atomic_add_int(&sp->length, sndout); len += sndout; + /* Did we reach EOR? */ if ((uio->uio_resid == 0) && ((user_marks_eor == 0) || @@ -11428,13 +11373,20 @@ sctp_lower_sosend(struct socket *so, } } SCTP_TCB_SEND_LOCK(stcb); - if (sp->msg_is_complete == 0) { - strm->last_msg_incomplete = 1; - asoc->stream_locked = 1; - asoc->stream_locked_on = srcv->sinfo_stream; + if (sp) { + if (sp->msg_is_complete == 0) { + strm->last_msg_incomplete = 1; + asoc->stream_locked = 1; + asoc->stream_locked_on = srcv->sinfo_stream; + } else { + sp->sender_all_done = 1; + strm->last_msg_incomplete = 0; + asoc->stream_locked = 0; + } } else { strm->last_msg_incomplete = 0; asoc->stream_locked = 0; + } SCTP_TCB_SEND_UNLOCK(stcb); if (uio->uio_resid == 0) { |