Fix several bugs in the stream schedulers.
From Robin Seggelmann. MFC after: 3 months.
This commit is contained in:
parent
977ce16e84
commit
6c509b30f6
@ -12342,7 +12342,7 @@ sctp_lower_sosend(struct socket *so,
|
||||
TAILQ_INIT(&asoc->strmout[i].outqueue);
|
||||
asoc->strmout[i].stream_no = i;
|
||||
asoc->strmout[i].last_msg_incomplete = 0;
|
||||
asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i]);
|
||||
asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*-
|
||||
* Copyright (c) 2010, by Randall Stewart & Michael Tuexen,
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2010-2011, by Randall Stewart, rrs@lakerest.net and
|
||||
* Michael Tuexen, tuexen@fh-muenster.de
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@ -56,6 +57,11 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
uint16_t i;
|
||||
|
||||
TAILQ_INIT(&asoc->ss_data.out_wheel);
|
||||
/*
|
||||
* If there is data in the stream queues already, the scheduler of
|
||||
* an existing association has been changed. We need to add all
|
||||
* stream queues to the wheel.
|
||||
*/
|
||||
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
|
||||
if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
|
||||
sctp_ss_default_add(stcb, &stcb->asoc,
|
||||
@ -83,7 +89,7 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_ss_default_init_stream(struct sctp_stream_out *strq)
|
||||
sctp_ss_default_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
|
||||
{
|
||||
strq->ss_params.rr.next_spoke.tqe_next = NULL;
|
||||
strq->ss_params.rr.next_spoke.tqe_prev = NULL;
|
||||
@ -411,11 +417,15 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_ss_prio_init_stream(struct sctp_stream_out *strq)
|
||||
sctp_ss_prio_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
|
||||
{
|
||||
strq->ss_params.prio.next_spoke.tqe_next = NULL;
|
||||
strq->ss_params.prio.next_spoke.tqe_prev = NULL;
|
||||
strq->ss_params.prio.priority = 0;
|
||||
if (with_strq != NULL) {
|
||||
strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
|
||||
} else {
|
||||
strq->ss_params.prio.priority = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -575,11 +585,15 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_ss_fb_init_stream(struct sctp_stream_out *strq)
|
||||
sctp_ss_fb_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
|
||||
{
|
||||
strq->ss_params.fb.next_spoke.tqe_next = NULL;
|
||||
strq->ss_params.fb.next_spoke.tqe_prev = NULL;
|
||||
strq->ss_params.fb.rounds = -1;
|
||||
if (with_strq != NULL) {
|
||||
strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
|
||||
} else {
|
||||
strq->ss_params.fb.rounds = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -697,28 +711,40 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
* Maintains the order provided by the application.
|
||||
*/
|
||||
static void
|
||||
sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
|
||||
int holds_lock);
|
||||
|
||||
static void
|
||||
sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
int holds_lock)
|
||||
{
|
||||
int x, element = 0, add_more = 1;
|
||||
uint32_t x, n = 0, add_more = 1;
|
||||
struct sctp_stream_queue_pending *sp;
|
||||
uint16_t i;
|
||||
|
||||
TAILQ_INIT(&asoc->ss_data.out_list);
|
||||
/*
|
||||
* If there is data in the stream queues already, the scheduler of
|
||||
* an existing association has been changed. We can only cycle
|
||||
* through the stream queues and add everything to the FCFS queue.
|
||||
*/
|
||||
while (add_more) {
|
||||
add_more = 0;
|
||||
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
|
||||
sp = TAILQ_FIRST(&asoc->ss_data.out_list);
|
||||
x = element;
|
||||
while (sp != NULL && x > 0) {
|
||||
sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
|
||||
x = 0;
|
||||
/* Find n. message in current stream queue */
|
||||
while (sp != NULL && x < n) {
|
||||
sp = TAILQ_NEXT(sp, next);
|
||||
x++;
|
||||
}
|
||||
if (sp != NULL) {
|
||||
sctp_ss_default_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock);
|
||||
sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, holds_lock);
|
||||
add_more = 1;
|
||||
}
|
||||
}
|
||||
element++;
|
||||
n++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -729,14 +755,14 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
{
|
||||
if (clear_values) {
|
||||
while (!TAILQ_EMPTY(&asoc->ss_data.out_list)) {
|
||||
TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), next);
|
||||
TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), ss_next);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_ss_fcfs_init_stream(struct sctp_stream_out *strq)
|
||||
sctp_ss_fcfs_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
|
||||
{
|
||||
/* Nothing to be done here */
|
||||
return;
|
||||
@ -750,9 +776,9 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
if (holds_lock == 0) {
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
}
|
||||
if (sp && (sp->next.tqe_next == NULL) &&
|
||||
(sp->next.tqe_prev == NULL)) {
|
||||
TAILQ_INSERT_TAIL(&asoc->ss_data.out_list, sp, next);
|
||||
if (sp && (sp->ss_next.tqe_next == NULL) &&
|
||||
(sp->ss_next.tqe_prev == NULL)) {
|
||||
TAILQ_INSERT_TAIL(&asoc->ss_data.out_list, sp, ss_next);
|
||||
}
|
||||
if (holds_lock == 0) {
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
@ -779,9 +805,9 @@ sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
}
|
||||
if (sp &&
|
||||
((sp->next.tqe_next != NULL) ||
|
||||
(sp->next.tqe_prev != NULL))) {
|
||||
TAILQ_REMOVE(&asoc->ss_data.out_list, sp, next);
|
||||
((sp->ss_next.tqe_next != NULL) ||
|
||||
(sp->ss_next.tqe_prev != NULL))) {
|
||||
TAILQ_REMOVE(&asoc->ss_data.out_list, sp, ss_next);
|
||||
}
|
||||
if (holds_lock == 0) {
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
@ -819,7 +845,7 @@ sctp_ss_fcfs_select(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
if (TAILQ_FIRST(&strq->outqueue) &&
|
||||
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
|
||||
TAILQ_FIRST(&strq->outqueue)->net != net) {
|
||||
sp = TAILQ_NEXT(sp, next);
|
||||
sp = TAILQ_NEXT(sp, ss_next);
|
||||
goto default_again;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2011, by Randall Stewart, rrs@lakerest.net and
|
||||
* Michael Tuexen, tuexen@fh-muenster.de
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@ -475,6 +478,7 @@ struct sctp_stream_queue_pending {
|
||||
struct timeval ts;
|
||||
struct sctp_nets *net;
|
||||
TAILQ_ENTRY(sctp_stream_queue_pending) next;
|
||||
TAILQ_ENTRY(sctp_stream_queue_pending) ss_next;
|
||||
uint32_t length;
|
||||
uint32_t timetolive;
|
||||
uint32_t ppid;
|
||||
@ -652,7 +656,7 @@ struct sctp_ss_functions {
|
||||
int holds_lock);
|
||||
void (*sctp_ss_clear) (struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
int clear_values, int holds_lock);
|
||||
void (*sctp_ss_init_stream) (struct sctp_stream_out *strq);
|
||||
void (*sctp_ss_init_stream) (struct sctp_stream_out *strq, struct sctp_stream_out *with_strq);
|
||||
void (*sctp_ss_add_to_stream) (struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock);
|
||||
int (*sctp_ss_is_empty) (struct sctp_tcb *stcb, struct sctp_association *asoc);
|
||||
@ -751,12 +755,7 @@ struct sctp_association {
|
||||
/* re-assembly queue for fragmented chunks on the inbound path */
|
||||
struct sctpchunk_listhead reasmqueue;
|
||||
|
||||
/*
|
||||
* this queue is used when we reach a condition that we can NOT put
|
||||
* data into the socket buffer. We track the size of this queue and
|
||||
* set our rwnd to the space in the socket minus also the
|
||||
* size_on_delivery_queue.
|
||||
*/
|
||||
/* Scheduling queues */
|
||||
union scheduling_data ss_data;
|
||||
|
||||
/*
|
||||
|
@ -1,5 +1,8 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2011, by Randall Stewart, rrs@lakerest.net and
|
||||
* Michael Tuexen, tuexen@fh-muenster.de
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@ -1510,32 +1513,17 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
|
||||
stcb->asoc.sent_queue_retran_cnt);
|
||||
stcb->asoc.sent_queue_retran_cnt = 0;
|
||||
}
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
if (stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) {
|
||||
int cnt = 0;
|
||||
|
||||
/* Check to see if a spoke fell off the wheel */
|
||||
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
|
||||
if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
|
||||
stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb,
|
||||
&stcb->asoc,
|
||||
&stcb->asoc.strmout[i],
|
||||
NULL,
|
||||
1);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
if (cnt) {
|
||||
/* yep, we lost a spoke or two */
|
||||
SCTP_PRINTF("Found an additional %d streams NOT on outwheel, corrected\n", cnt);
|
||||
/* No stream scheduler information, initialize scheduler */
|
||||
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 0);
|
||||
if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) {
|
||||
/* yep, we lost a stream or two */
|
||||
SCTP_PRINTF("Found additional streams NOT managed by scheduler, corrected\n");
|
||||
} else {
|
||||
/* no spokes lost, */
|
||||
/* no streams lost */
|
||||
stcb->asoc.total_output_queue_size = 0;
|
||||
}
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
return;
|
||||
}
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
/* Check to see if some data queued, if so report it */
|
||||
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
|
||||
if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
|
||||
|
@ -3448,7 +3448,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent;
|
||||
stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
|
||||
stcb->asoc.strmout[i].stream_no = i;
|
||||
stcb->asoc.ss_functions.sctp_ss_init_stream(&oldstream[i]);
|
||||
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
|
||||
/*
|
||||
* now anything on those
|
||||
* queues?
|
||||
@ -3475,7 +3475,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
|
||||
stcb->asoc.strmout[i].stream_no = i;
|
||||
stcb->asoc.strmout[i].last_msg_incomplete = 0;
|
||||
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i]);
|
||||
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
|
||||
}
|
||||
stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt;
|
||||
SCTP_FREE(oldstream, SCTP_M_STRMO);
|
||||
|
@ -1076,7 +1076,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
TAILQ_INIT(&asoc->strmout[i].outqueue);
|
||||
asoc->strmout[i].stream_no = i;
|
||||
asoc->strmout[i].last_msg_incomplete = 0;
|
||||
asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i]);
|
||||
asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL);
|
||||
}
|
||||
asoc->ss_functions.sctp_ss_init(stcb, asoc, 0);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user