summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_output.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-04-19 11:28:43 +0000
committerrrs <rrs@FreeBSD.org>2007-04-19 11:28:43 +0000
commite8a77bd9270dfbfa30aa44607f5f3ecb4e70ee3e (patch)
treed950582b945c3e6f66e506197c41a7fa14d07c72 /sys/netinet/sctp_output.c
parent19613c2bfe0ba59b977ac06457e84b93cceb5045 (diff)
downloadFreeBSD-src-e8a77bd9270dfbfa30aa44607f5f3ecb4e70ee3e.zip
FreeBSD-src-e8a77bd9270dfbfa30aa44607f5f3ecb4e70ee3e.tar.gz
- More work on making send lock contention.
- Removed free-oqueue cache. - Fix counter for sq entries - Increased the amount of information retained on ASOC_TSN logging on the association. - Made it so with the ASOC_TSN logging on sending or recieving an abort we dump the log. - Went through and added invariant's around some panic's that needed them. - decrements went to atomic_subtact_int instead of add -1 - Removed residual count increment that threw off a strm oq count. - Tracks and complaints if we don't have a LAST fragment and clean up the sp structure. - Track a new stat that counts number of abandoned msgs that happen if you close without reading. - Fix lookup of frag point to be aware of a 0 assoc-id. Reviewed by: gnn
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r--sys/netinet/sctp_output.c131
1 files changed, 97 insertions, 34 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index e1ee546..304d299 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -3587,6 +3587,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
if (ret)
SCTP_STAT_INCR(sctps_senderrors);
+
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_OUTPUT3) {
printf("Ip output returns %d\n", ret);
@@ -5371,7 +5372,6 @@ sctp_msg_append(struct sctp_tcb *stcb,
error = ENOMEM;
goto out_now;
}
- SCTP_INCR_STRMOQ_COUNT();
sp->sinfo_flags = srcv->sinfo_flags;
sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid;
@@ -6084,15 +6084,16 @@ sctp_can_we_split_this(struct sctp_tcb *stcb,
* 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 (stcb->asoc.total_flight > 0)
- return (0);
- else
+ if (stcb->asoc.total_flight == 0) {
+ /*
+ * If nothing is in flight, we zero the
+ * packet counter.
+ */
return (sp->length);
+ }
+ return (0);
+
} else {
/* You can fill the rest */
return (goal_mtu);
@@ -6132,7 +6133,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
int to_move;
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);
@@ -6159,12 +6159,23 @@ one_more_time:
if (sp->length == 0) {
if (sp->sender_all_done) {
/*
- * We are doing deffered cleanup. Last time
+ * We are doing differed 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;
+ if (sp->put_last_out == 0) {
+ printf("Gak, put out entire msg with NO end!-1\n");
+ printf("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n",
+ sp->sender_all_done,
+ sp->length,
+ sp->msg_is_complete,
+ sp->put_last_out,
+ send_lock_up);
+ }
+ if (TAILQ_NEXT(sp, next) == NULL) {
+ 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);
@@ -6206,6 +6217,7 @@ one_more_time:
if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
sp->msg_is_complete = 1;
}
+re_look:
if (sp->msg_is_complete) {
/* The message is complete */
to_move = min(sp->length, frag_point);
@@ -6213,8 +6225,10 @@ one_more_time:
/* All of it fits in the MTU */
if (sp->some_taken) {
rcv_flags |= SCTP_DATA_LAST_FRAG;
+ sp->put_last_out = 1;
} else {
rcv_flags |= SCTP_DATA_NOT_FRAG;
+ sp->put_last_out = 1;
}
} else {
/* Not all of it fits, we fragment */
@@ -6227,14 +6241,37 @@ one_more_time:
to_move = sctp_can_we_split_this(stcb, sp, goal_mtu,
frag_point, eeor_mode);
if (to_move) {
- if (to_move >= sp->length) {
- to_move = sp->length;
+ /*-
+ * We use a snapshot of length in case it
+ * is expanding during the compare.
+ */
+ uint32_t llen;
+
+ llen = sp->length;
+ if (to_move >= llen) {
+ to_move = llen;
+ if (send_lock_up == 0) {
+ /*-
+ * We are taking all of an incomplete msg
+ * thus we need a send lock.
+ */
+ SCTP_TCB_SEND_LOCK(stcb);
+ send_lock_up = 1;
+ if (sp->msg_is_complete) {
+ /*
+ * the sender finished the
+ * msg
+ */
+ goto re_look;
+ }
+ }
}
if (sp->some_taken == 0) {
rcv_flags |= SCTP_DATA_FIRST_FRAG;
+ sp->some_taken = 1;
}
- sp->some_taken = 1;
} else {
+ /* Nothing to take. */
if (sp->some_taken) {
*locked = 1;
}
@@ -6270,21 +6307,12 @@ out_gu:
} 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;
chk->last_mbuf = sp->tail_mbuf;
/* register the stealing */
sp->data = sp->tail_mbuf = NULL;
- took_all = 1;
} else {
struct mbuf *m;
@@ -6303,16 +6331,35 @@ out_gu:
sp->data = SCTP_BUF_NEXT(m);
SCTP_BUF_NEXT(m) = NULL;
if (sp->tail_mbuf == m) {
- /* freeing tail */
+ /*-
+ * Freeing tail? TSNH since
+ * we supposedly were taking less
+ * than the sp->length.
+ */
+#ifdef INVARIANTS
+ panic("Huh, freing tail? - TSNH");
+#else
printf("Huh, freeing tail? - TSNH\n");
- sp->tail_mbuf = sp->data;
+ sp->tail_mbuf = sp->data = NULL;
+ sp->length = 0;
+#endif
+
}
sctp_m_free(m);
m = sp->data;
}
}
if (to_move > sp->length) {
+ /*- This should not happen either
+ * since we always lower to_move to the size
+ * of sp->length if its larger.
+ */
+#ifdef INVARIANTS
panic("Huh, how can to_move be larger?");
+#else
+ printf("Huh, how can to_move be larger?\n");
+ sp->length = 0;
+#endif
} else {
atomic_subtract_int(&sp->length, to_move);
}
@@ -6331,7 +6378,7 @@ out_gu:
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
}
- if (took_all) {
+ if (chk->data == NULL) {
/* unsteal the data */
sp->data = chk->data;
sp->tail_mbuf = chk->last_mbuf;
@@ -6344,7 +6391,7 @@ out_gu:
SCTP_BUF_NEXT(sp->data) = m;
}
sp->some_taken = some_taken;
- sp->length += to_move;
+ atomic_add_int(&sp->length, to_move);
chk->data = NULL;
sctp_free_a_chunk(stcb, chk);
goto out_gu;
@@ -6357,9 +6404,13 @@ out_gu:
}
SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_DONTWAIT);
if (chk->data == NULL) {
- /* HELP */
+ /* HELP, TSNH since we assured it would not above? */
+#ifdef INVARIANTS
+ panic("prepend failes HELP?");
+#else
printf("prepend fails HELP?\n");
sctp_free_a_chunk(stcb, chk);
+#endif
goto out_gu;
}
sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
@@ -6414,9 +6465,12 @@ out_gu:
asoc->out_tsnlog[asoc->tsn_out_at].tsn = chk->rec.data.TSN_seq;
asoc->out_tsnlog[asoc->tsn_out_at].strm = chk->rec.data.stream_number;
asoc->out_tsnlog[asoc->tsn_out_at].seq = chk->rec.data.stream_seq;
+ asoc->out_tsnlog[asoc->tsn_out_at].sz = chk->send_size;
+ asoc->out_tsnlog[asoc->tsn_out_at].flgs = chk->rec.data.rcv_flags;
asoc->tsn_out_at++;
if (asoc->tsn_out_at >= SCTP_TSN_LOG_SIZE) {
asoc->tsn_out_at = 0;
+ asoc->tsn_out_wrapped = 1;
}
#endif
@@ -6450,7 +6504,16 @@ out_gu:
if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) {
/* All done pull and kill the message */
atomic_subtract_int(&asoc->stream_queue_cnt, 1);
- if (send_lock_up == 0) {
+ if (sp->put_last_out == 0) {
+ printf("Gak, put out entire msg with NO end!-2\n");
+ printf("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n",
+ sp->sender_all_done,
+ sp->length,
+ sp->msg_is_complete,
+ sp->put_last_out,
+ send_lock_up);
+ }
+ if ((send_lock_up == 0) && (TAILQ_NEXT(sp, next) == NULL)) {
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
}
@@ -10422,7 +10485,6 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
*error = ENOMEM;
goto out_now;
}
- SCTP_INCR_STRMOQ_COUNT();
sp->act_flags = 0;
sp->sender_all_done = 0;
sp->sinfo_flags = srcv->sinfo_flags;
@@ -10445,6 +10507,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
}
sp->sender_all_done = 0;
sp->some_taken = 0;
+ sp->put_last_out = 0;
resv_in_first = sizeof(struct sctp_data_chunk);
sp->data = sp->tail_mbuf = NULL;
*error = sctp_copy_one(sp, uio, resv_in_first);
@@ -11105,9 +11168,7 @@ sctp_lower_sosend(struct socket *so,
sp->sender_all_done = 0;
}
sctp_snd_sb_alloc(stcb, sp->length);
-
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;
#ifdef SCTP_LOG_SENDING_STR
@@ -11119,7 +11180,7 @@ sctp_lower_sosend(struct socket *so,
} else {
SCTP_STAT_INCR(sctps_sends_with_unord);
}
-
+ TAILQ_INSERT_TAIL(&strm->outqueue, sp, next);
if ((strm->next_spoke.tqe_next == NULL) &&
(strm->next_spoke.tqe_prev == NULL)) {
/* Not on wheel, insert */
@@ -11195,6 +11256,7 @@ sctp_lower_sosend(struct socket *so,
/* Did we reach EOR? */
if ((uio->uio_resid == 0) &&
((user_marks_eor == 0) ||
+ (srcv->sinfo_flags & SCTP_EOF) ||
(user_marks_eor && (srcv->sinfo_flags & SCTP_EOR)))
) {
sp->msg_is_complete = 1;
@@ -11384,6 +11446,7 @@ sctp_lower_sosend(struct socket *so,
asoc->stream_locked = 0;
}
} else {
+ printf("Huh no sp TSNH?\n");
strm->last_msg_incomplete = 0;
asoc->stream_locked = 0;
OpenPOWER on IntegriCloud