/*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved. * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved. * Copyright (c) 2010-2012, by Robin Seggelmann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * b) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE.
*/
asoc->ss_data.locked_on_sending = NULL;
asoc->ss_data.last_out_stream = NULL;
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 < asoc->streamoutcnt; i++) {
stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc,
&asoc->strmout[i],
NULL);
} return;
}
/* Add to wheel if not already on it and stream queue not empty */ if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
strq, ss_params.ss.rr.next_spoke);
strq->ss_params.scheduled = true;
} return;
}
if (asoc->ss_data.locked_on_sending != NULL) {
KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
("locked_on_sending %p not scheduled",
(void *)asoc->ss_data.locked_on_sending)); return (asoc->ss_data.locked_on_sending);
}
strqt = asoc->ss_data.last_out_stream;
KASSERT(strqt == NULL || strqt->ss_params.scheduled,
("last_out_stream %p not scheduled", (void *)strqt));
default_again: /* Find the next stream to use */ if (strqt == NULL) {
strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); if (strq == NULL) {
strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
KASSERT(strq == NULL || strq->ss_params.scheduled,
("strq %p not scheduled", (void *)strq));
/* If CMT is off, we must validate that * the stream in question has the first * item pointed towards are network destination * requested by the caller. Note that if we * turn out to be locked to a stream (assigning * TSN's then we must stop, since we cannot * look for another stream with data to send * to that destination). In CMT's case, by * skipping this check, we will send one * data packet towards the requested net.
*/ if (net != NULL && strq != NULL &&
SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) { if (strq == asoc->ss_data.last_out_stream) { return (NULL);
} else {
strqt = strq; goto default_again;
}
}
} return (strq);
}
/* * Real round-robin per packet algorithm. * Always iterates the streams in ascending order and * only fills messages of the same stream in a packet.
*/ staticstruct sctp_stream_out *
sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, struct sctp_association *asoc)
{
SCTP_TCB_LOCK_ASSERT(stcb);
strqt = asoc->ss_data.last_out_stream;
KASSERT(strqt == NULL || strqt->ss_params.scheduled,
("last_out_stream %p not scheduled", (void *)strqt));
rrp_again: /* Find the next stream to use */ if (strqt == NULL) {
strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); if (strq == NULL) {
strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
KASSERT(strq == NULL || strq->ss_params.scheduled,
("strq %p not scheduled", (void *)strq));
/* If CMT is off, we must validate that * the stream in question has the first * item pointed towards are network destination * requested by the caller. Note that if we * turn out to be locked to a stream (assigning * TSN's then we must stop, since we cannot * look for another stream with data to send * to that destination). In CMT's case, by * skipping this check, we will send one * data packet towards the requested net.
*/ if (net != NULL && strq != NULL &&
SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) { if (strq == asoc->ss_data.last_out_stream) {
strq = NULL;
} else {
strqt = strq; goto rrp_again;
}
}
}
asoc->ss_data.last_out_stream = strq; return;
}
/* * Priority algorithm. * Always prefers streams based on their priority id.
*/ staticvoid
sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, bool clear_values)
{
SCTP_TCB_LOCK_ASSERT(stcb);
while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { struct sctp_stream_out *strq;
if (asoc->ss_data.locked_on_sending != NULL) {
KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
("locked_on_sending %p not scheduled",
(void *)asoc->ss_data.locked_on_sending)); return (asoc->ss_data.locked_on_sending);
}
strqt = asoc->ss_data.last_out_stream;
KASSERT(strqt == NULL || strqt->ss_params.scheduled,
("last_out_stream %p not scheduled", (void *)strqt));
prio_again: /* Find the next stream to use */ if (strqt == NULL) {
strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
strqn = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke); if (strqn != NULL &&
strqn->ss_params.ss.prio.priority == strqt->ss_params.ss.prio.priority) {
strq = strqn;
} else {
strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
KASSERT(strq == NULL || strq->ss_params.scheduled,
("strq %p not scheduled", (void *)strq));
/* If CMT is off, we must validate that * the stream in question has the first * item pointed towards are network destination * requested by the caller. Note that if we * turn out to be locked to a stream (assigning * TSN's then we must stop, since we cannot * look for another stream with data to send * to that destination). In CMT's case, by * skipping this check, we will send one * data packet towards the requested net.
*/ if (net != NULL && strq != NULL &&
SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) { if (strq == asoc->ss_data.last_out_stream) { return (NULL);
} else {
strqt = strq; goto prio_again;
}
}
} return (strq);
}
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 < asoc->streamoutcnt; i++) {
sp = TAILQ_FIRST(&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_fcfs_add(stcb, asoc, &asoc->strmout[i], sp);
add_more = 1;
}
}
n++;
} return;
}
/* * If CMT is off, we must validate that * the stream in question has the first * item pointed towards are network destination * requested by the caller. Note that if we * turn out to be locked to a stream (assigning * TSN's then we must stop, since we cannot * look for another stream with data to send * to that destination). In CMT's case, by * skipping this check, we will send one * data packet towards the requested net.
*/ if (net != NULL && strq != NULL &&
SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) {
sp = TAILQ_NEXT(sp, ss_next); goto default_again;
}
} return (strq);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.