1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved.
5 * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved.
6 * Copyright (c) 2010-2012, by Robin Seggelmann. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * a) Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * b) Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <netinet/sctp_pcb.h>
35
36 /*
37 * Default simple round-robin algorithm.
38 * Just iterates the streams in the order they appear.
39 */
40
41 static void
42 sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
43 struct sctp_stream_out *,
44 struct sctp_stream_queue_pending *);
45
46 static void
47 sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
48 struct sctp_stream_out *,
49 struct sctp_stream_queue_pending *);
50
51 static void
52 sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc)
53 {
54 uint16_t i;
55
56 SCTP_TCB_LOCK_ASSERT(stcb);
57
58 asoc->ss_data.locked_on_sending = NULL;
59 asoc->ss_data.last_out_stream = NULL;
60 TAILQ_INIT(&asoc->ss_data.out.wheel);
61 /*
62 * If there is data in the stream queues already, the scheduler of
63 * an existing association has been changed. We need to add all
64 * stream queues to the wheel.
65 */
66 for (i = 0; i < asoc->streamoutcnt; i++) {
67 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc,
68 &asoc->strmout[i],
69 NULL);
70 }
71 return;
72 }
73
74 static void
75 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
76 bool clear_values SCTP_UNUSED)
77 {
78 SCTP_TCB_LOCK_ASSERT(stcb);
79
80 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
81 struct sctp_stream_out *strq;
82
83 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
84 KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq));
85 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
86 strq->ss_params.scheduled = false;
87 }
88 asoc->ss_data.last_out_stream = NULL;
89 return;
90 }
91
92 static void
93 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
94 {
95 SCTP_TCB_LOCK_ASSERT(stcb);
96
97 if (with_strq != NULL) {
98 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
99 stcb->asoc.ss_data.locked_on_sending = strq;
100 }
101 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
102 stcb->asoc.ss_data.last_out_stream = strq;
103 }
104 }
105 strq->ss_params.scheduled = false;
106 return;
107 }
108
109 static void
110 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
111 struct sctp_stream_out *strq,
112 struct sctp_stream_queue_pending *sp SCTP_UNUSED)
113 {
114 SCTP_TCB_LOCK_ASSERT(stcb);
115
116 /* Add to wheel if not already on it and stream queue not empty */
117 if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
118 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
119 strq, ss_params.ss.rr.next_spoke);
120 strq->ss_params.scheduled = true;
121 }
122 return;
123 }
124
125 static bool
126 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
127 {
128 SCTP_TCB_LOCK_ASSERT(stcb);
129
130 return (TAILQ_EMPTY(&asoc->ss_data.out.wheel));
131 }
132
133 static void
134 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
135 struct sctp_stream_out *strq,
136 struct sctp_stream_queue_pending *sp SCTP_UNUSED)
137 {
138 SCTP_TCB_LOCK_ASSERT(stcb);
139
140 /*
141 * Remove from wheel if stream queue is empty and actually is on the
142 * wheel
143 */
144 if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) {
145 if (asoc->ss_data.last_out_stream == strq) {
146 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
147 sctpwheel_listhead,
148 ss_params.ss.rr.next_spoke);
149 if (asoc->ss_data.last_out_stream == NULL) {
150 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
151 sctpwheel_listhead);
152 }
153 if (asoc->ss_data.last_out_stream == strq) {
154 asoc->ss_data.last_out_stream = NULL;
155 }
156 }
157 if (asoc->ss_data.locked_on_sending == strq) {
158 asoc->ss_data.locked_on_sending = NULL;
159 }
160 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
161 strq->ss_params.scheduled = false;
162 }
163 return;
164 }
165
166 static struct sctp_stream_out *
167 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
168 struct sctp_association *asoc)
169 {
170 struct sctp_stream_out *strq, *strqt;
171
172 SCTP_TCB_LOCK_ASSERT(stcb);
173
174 if (asoc->ss_data.locked_on_sending != NULL) {
175 KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
176 ("locked_on_sending %p not scheduled",
177 (void *)asoc->ss_data.locked_on_sending));
178 return (asoc->ss_data.locked_on_sending);
179 }
180 strqt = asoc->ss_data.last_out_stream;
181 KASSERT(strqt == NULL || strqt->ss_params.scheduled,
182 ("last_out_stream %p not scheduled", (void *)strqt));
183 default_again:
184 /* Find the next stream to use */
185 if (strqt == NULL) {
186 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
187 } else {
188 strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke);
189 if (strq == NULL) {
190 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
191 }
192 }
193 KASSERT(strq == NULL || strq->ss_params.scheduled,
194 ("strq %p not scheduled", (void *)strq));
195
196 /*
197 * If CMT is off, we must validate that the stream in question has
198 * the first item pointed towards are network destination requested
199 * by the caller. Note that if we turn out to be locked to a stream
200 * (assigning TSN's then we must stop, since we cannot look for
201 * another stream with data to send to that destination). In CMT's
202 * case, by skipping this check, we will send one data packet
203 * towards the requested net.
204 */
205 if (net != NULL && strq != NULL &&
206 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
207 if (TAILQ_FIRST(&strq->outqueue) &&
208 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
209 TAILQ_FIRST(&strq->outqueue)->net != net) {
210 if (strq == asoc->ss_data.last_out_stream) {
211 return (NULL);
212 } else {
213 strqt = strq;
214 goto default_again;
215 }
216 }
217 }
218 return (strq);
219 }
220
221 static void
222 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
223 struct sctp_nets *net SCTP_UNUSED,
224 struct sctp_association *asoc,
225 struct sctp_stream_out *strq,
226 int moved_how_much SCTP_UNUSED)
227 {
228 struct sctp_stream_queue_pending *sp;
229
230 KASSERT(strq != NULL, ("strq is NULL"));
231 KASSERT(strq->ss_params.scheduled, ("strq %p is not scheduled", (void *)strq));
232 SCTP_TCB_LOCK_ASSERT(stcb);
233
234 asoc->ss_data.last_out_stream = strq;
235 if (asoc->idata_supported == 0) {
236 sp = TAILQ_FIRST(&strq->outqueue);
237 if ((sp != NULL) && (sp->some_taken == 1)) {
238 asoc->ss_data.locked_on_sending = strq;
239 } else {
240 asoc->ss_data.locked_on_sending = NULL;
241 }
242 } else {
243 asoc->ss_data.locked_on_sending = NULL;
244 }
245 return;
246 }
247
248 static void
249 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
250 struct sctp_association *asoc SCTP_UNUSED)
251 {
252 SCTP_TCB_LOCK_ASSERT(stcb);
253
254 /* Nothing to be done here */
255 return;
256 }
257
258 static int
259 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
260 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
261 {
262 SCTP_TCB_LOCK_ASSERT(stcb);
263
264 /* Nothing to be done here */
265 return (-1);
266 }
267
268 static int
269 sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
270 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED)
271 {
272 SCTP_TCB_LOCK_ASSERT(stcb);
273
274 /* Nothing to be done here */
275 return (-1);
276 }
277
278 static bool
279 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
280 {
281 struct sctp_stream_out *strq;
282 struct sctp_stream_queue_pending *sp;
283
284 SCTP_TCB_LOCK_ASSERT(stcb);
285
286 if (asoc->stream_queue_cnt != 1) {
287 return (false);
288 }
289 strq = asoc->ss_data.locked_on_sending;
290 if (strq == NULL) {
291 return (false);
292 }
293 sp = TAILQ_FIRST(&strq->outqueue);
294 if (sp == NULL) {
295 return (false);
296 }
297 return (sp->msg_is_complete == 0);
298 }
299
300 /*
301 * Real round-robin algorithm.
302 * Always iterates the streams in ascending order.
303 */
304 static void
305 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
306 struct sctp_stream_out *strq,
307 struct sctp_stream_queue_pending *sp SCTP_UNUSED)
308 {
309 struct sctp_stream_out *strqt;
310
311 SCTP_TCB_LOCK_ASSERT(stcb);
312
313 if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
314 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
315 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
316 } else {
317 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
318 while (strqt != NULL && (strqt->sid < strq->sid)) {
319 strqt = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke);
320 }
321 if (strqt != NULL) {
322 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.rr.next_spoke);
323 } else {
324 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
325 }
326 }
327 strq->ss_params.scheduled = true;
328 }
329 return;
330 }
331
332 /*
333 * Real round-robin per packet algorithm.
334 * Always iterates the streams in ascending order and
335 * only fills messages of the same stream in a packet.
336 */
337 static struct sctp_stream_out *
338 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
339 struct sctp_association *asoc)
340 {
341 SCTP_TCB_LOCK_ASSERT(stcb);
342
343 return (asoc->ss_data.last_out_stream);
344 }
345
346 static void
347 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
348 struct sctp_association *asoc)
349 {
350 struct sctp_stream_out *strq, *strqt;
351
352 SCTP_TCB_LOCK_ASSERT(stcb);
353
354 strqt = asoc->ss_data.last_out_stream;
355 KASSERT(strqt == NULL || strqt->ss_params.scheduled,
356 ("last_out_stream %p not scheduled", (void *)strqt));
357 rrp_again:
358 /* Find the next stream to use */
359 if (strqt == NULL) {
360 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
361 } else {
362 strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke);
363 if (strq == NULL) {
364 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
365 }
366 }
367 KASSERT(strq == NULL || strq->ss_params.scheduled,
368 ("strq %p not scheduled", (void *)strq));
369
370 /*
371 * If CMT is off, we must validate that the stream in question has
372 * the first item pointed towards are network destination requested
373 * by the caller. Note that if we turn out to be locked to a stream
374 * (assigning TSN's then we must stop, since we cannot look for
375 * another stream with data to send to that destination). In CMT's
376 * case, by skipping this check, we will send one data packet
377 * towards the requested net.
378 */
379 if (net != NULL && strq != NULL &&
380 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
381 if (TAILQ_FIRST(&strq->outqueue) &&
382 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
383 TAILQ_FIRST(&strq->outqueue)->net != net) {
384 if (strq == asoc->ss_data.last_out_stream) {
385 strq = NULL;
386 } else {
387 strqt = strq;
388 goto rrp_again;
389 }
390 }
391 }
392 asoc->ss_data.last_out_stream = strq;
393 return;
394 }
395
396 /*
397 * Priority algorithm.
398 * Always prefers streams based on their priority id.
399 */
400 static void
401 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
402 bool clear_values)
403 {
404 SCTP_TCB_LOCK_ASSERT(stcb);
405
406 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
407 struct sctp_stream_out *strq;
408
409 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
410 KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq));
411 if (clear_values) {
412 strq->ss_params.ss.prio.priority = 0;
413 }
414 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
415 strq->ss_params.scheduled = false;
416 }
417 asoc->ss_data.last_out_stream = NULL;
418 return;
419 }
420
421 static void
422 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
423 {
424 SCTP_TCB_LOCK_ASSERT(stcb);
425
426 if (with_strq != NULL) {
427 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
428 stcb->asoc.ss_data.locked_on_sending = strq;
429 }
430 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
431 stcb->asoc.ss_data.last_out_stream = strq;
432 }
433 }
434 strq->ss_params.scheduled = false;
435 if (with_strq != NULL) {
436 strq->ss_params.ss.prio.priority = with_strq->ss_params.ss.prio.priority;
437 } else {
438 strq->ss_params.ss.prio.priority = 0;
439 }
440 return;
441 }
442
443 static void
444 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
445 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED)
446 {
447 struct sctp_stream_out *strqt;
448
449 SCTP_TCB_LOCK_ASSERT(stcb);
450
451 /* Add to wheel if not already on it and stream queue not empty */
452 if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
453 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
454 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
455 } else {
456 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
457 while (strqt != NULL && strqt->ss_params.ss.prio.priority < strq->ss_params.ss.prio.priority) {
458 strqt = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke);
459 }
460 if (strqt != NULL) {
461 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.prio.next_spoke);
462 } else {
463 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
464 }
465 }
466 strq->ss_params.scheduled = true;
467 }
468 return;
469 }
470
471 static void
472 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
473 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED)
474 {
475 SCTP_TCB_LOCK_ASSERT(stcb);
476
477 /*
478 * Remove from wheel if stream queue is empty and actually is on the
479 * wheel
480 */
481 if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) {
482 if (asoc->ss_data.last_out_stream == strq) {
483 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
484 sctpwheel_listhead,
485 ss_params.ss.prio.next_spoke);
486 if (asoc->ss_data.last_out_stream == NULL) {
487 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
488 sctpwheel_listhead);
489 }
490 if (asoc->ss_data.last_out_stream == strq) {
491 asoc->ss_data.last_out_stream = NULL;
492 }
493 }
494 if (asoc->ss_data.locked_on_sending == strq) {
495 asoc->ss_data.locked_on_sending = NULL;
496 }
497 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
498 strq->ss_params.scheduled = false;
499 }
500 return;
501 }
502
503 static struct sctp_stream_out *
504 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
505 struct sctp_association *asoc)
506 {
507 struct sctp_stream_out *strq, *strqt, *strqn;
508
509 SCTP_TCB_LOCK_ASSERT(stcb);
510
511 if (asoc->ss_data.locked_on_sending != NULL) {
512 KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
513 ("locked_on_sending %p not scheduled",
514 (void *)asoc->ss_data.locked_on_sending));
515 return (asoc->ss_data.locked_on_sending);
516 }
517 strqt = asoc->ss_data.last_out_stream;
518 KASSERT(strqt == NULL || strqt->ss_params.scheduled,
519 ("last_out_stream %p not scheduled", (void *)strqt));
520 prio_again:
521 /* Find the next stream to use */
522 if (strqt == NULL) {
523 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
524 } else {
525 strqn = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke);
526 if (strqn != NULL &&
527 strqn->ss_params.ss.prio.priority == strqt->ss_params.ss.prio.priority) {
528 strq = strqn;
529 } else {
530 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
531 }
532 }
533 KASSERT(strq == NULL || strq->ss_params.scheduled,
534 ("strq %p not scheduled", (void *)strq));
535
536 /*
537 * If CMT is off, we must validate that the stream in question has
538 * the first item pointed towards are network destination requested
539 * by the caller. Note that if we turn out to be locked to a stream
540 * (assigning TSN's then we must stop, since we cannot look for
541 * another stream with data to send to that destination). In CMT's
542 * case, by skipping this check, we will send one data packet
543 * towards the requested net.
544 */
545 if (net != NULL && strq != NULL &&
546 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
547 if (TAILQ_FIRST(&strq->outqueue) &&
548 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
549 TAILQ_FIRST(&strq->outqueue)->net != net) {
550 if (strq == asoc->ss_data.last_out_stream) {
551 return (NULL);
552 } else {
553 strqt = strq;
554 goto prio_again;
555 }
556 }
557 }
558 return (strq);
559 }
560
561 static int
562 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
563 struct sctp_stream_out *strq, uint16_t *value)
564 {
565 SCTP_TCB_LOCK_ASSERT(stcb);
566
567 if (strq == NULL) {
568 return (-1);
569 }
570 *value = strq->ss_params.ss.prio.priority;
571 return (1);
572 }
573
574 static int
575 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
576 struct sctp_stream_out *strq, uint16_t value)
577 {
578 SCTP_TCB_LOCK_ASSERT(stcb);
579
580 if (strq == NULL) {
581 return (-1);
582 }
583 strq->ss_params.ss.prio.priority = value;
584 sctp_ss_prio_remove(stcb, asoc, strq, NULL);
585 sctp_ss_prio_add(stcb, asoc, strq, NULL);
586 return (1);
587 }
588
589 /*
590 * Fair bandwidth algorithm.
591 * Maintains an equal throughput per stream.
592 */
593 static void
594 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
595 bool clear_values)
596 {
597 SCTP_TCB_LOCK_ASSERT(stcb);
598
599 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
600 struct sctp_stream_out *strq;
601
602 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
603 KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq));
604 if (clear_values) {
605 strq->ss_params.ss.fb.rounds = -1;
606 }
607 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke);
608 strq->ss_params.scheduled = false;
609 }
610 asoc->ss_data.last_out_stream = NULL;
611 return;
612 }
613
614 static void
615 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
616 {
617 SCTP_TCB_LOCK_ASSERT(stcb);
618
619 if (with_strq != NULL) {
620 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
621 stcb->asoc.ss_data.locked_on_sending = strq;
622 }
623 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
624 stcb->asoc.ss_data.last_out_stream = strq;
625 }
626 }
627 strq->ss_params.scheduled = false;
628 if (with_strq != NULL) {
629 strq->ss_params.ss.fb.rounds = with_strq->ss_params.ss.fb.rounds;
630 } else {
631 strq->ss_params.ss.fb.rounds = -1;
632 }
633 return;
634 }
635
636 static void
637 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
638 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED)
639 {
640 SCTP_TCB_LOCK_ASSERT(stcb);
641
642 if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
643 if (strq->ss_params.ss.fb.rounds < 0)
644 strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
645 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke);
646 strq->ss_params.scheduled = true;
647 }
648 return;
649 }
650
651 static void
652 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
653 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED)
654 {
655 SCTP_TCB_LOCK_ASSERT(stcb);
656
657 /*
658 * Remove from wheel if stream queue is empty and actually is on the
659 * wheel
660 */
661 if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) {
662 if (asoc->ss_data.last_out_stream == strq) {
663 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
664 sctpwheel_listhead,
665 ss_params.ss.fb.next_spoke);
666 if (asoc->ss_data.last_out_stream == NULL) {
667 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
668 sctpwheel_listhead);
669 }
670 if (asoc->ss_data.last_out_stream == strq) {
671 asoc->ss_data.last_out_stream = NULL;
672 }
673 }
674 if (asoc->ss_data.locked_on_sending == strq) {
675 asoc->ss_data.locked_on_sending = NULL;
676 }
677 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke);
678 strq->ss_params.scheduled = false;
679 }
680 return;
681 }
682
683 static struct sctp_stream_out *
684 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
685 struct sctp_association *asoc)
686 {
687 struct sctp_stream_out *strq = NULL, *strqt;
688
689 SCTP_TCB_LOCK_ASSERT(stcb);
690
691 if (asoc->ss_data.locked_on_sending != NULL) {
692 KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
693 ("locked_on_sending %p not scheduled",
694 (void *)asoc->ss_data.locked_on_sending));
695 return (asoc->ss_data.locked_on_sending);
696 }
697 if (asoc->ss_data.last_out_stream == NULL ||
698 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
699 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
700 } else {
701 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.ss.fb.next_spoke);
702 }
703 do {
704 if ((strqt != NULL) &&
705 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
706 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
707 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
708 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
709 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
710 if ((strqt->ss_params.ss.fb.rounds >= 0) &&
711 ((strq == NULL) ||
712 (strqt->ss_params.ss.fb.rounds < strq->ss_params.ss.fb.rounds))) {
713 strq = strqt;
714 }
715 }
716 if (strqt != NULL) {
717 strqt = TAILQ_NEXT(strqt, ss_params.ss.fb.next_spoke);
718 } else {
719 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
720 }
721 } while (strqt != strq);
722 return (strq);
723 }
724
725 static void
726 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
727 struct sctp_association *asoc, struct sctp_stream_out *strq,
728 int moved_how_much SCTP_UNUSED)
729 {
730 struct sctp_stream_queue_pending *sp;
731 struct sctp_stream_out *strqt;
732 int subtract;
733
734 SCTP_TCB_LOCK_ASSERT(stcb);
735
736 if (asoc->idata_supported == 0) {
737 sp = TAILQ_FIRST(&strq->outqueue);
738 if ((sp != NULL) && (sp->some_taken == 1)) {
739 asoc->ss_data.locked_on_sending = strq;
740 } else {
741 asoc->ss_data.locked_on_sending = NULL;
742 }
743 } else {
744 asoc->ss_data.locked_on_sending = NULL;
745 }
746 subtract = strq->ss_params.ss.fb.rounds;
747 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.ss.fb.next_spoke) {
748 strqt->ss_params.ss.fb.rounds -= subtract;
749 if (strqt->ss_params.ss.fb.rounds < 0)
750 strqt->ss_params.ss.fb.rounds = 0;
751 }
752 if (TAILQ_FIRST(&strq->outqueue)) {
753 strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
754 } else {
755 strq->ss_params.ss.fb.rounds = -1;
756 }
757 asoc->ss_data.last_out_stream = strq;
758 return;
759 }
760
761 /*
762 * First-come, first-serve algorithm.
763 * Maintains the order provided by the application.
764 */
765 static void
766 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
767 struct sctp_stream_out *strq SCTP_UNUSED,
768 struct sctp_stream_queue_pending *sp);
769
770 static void
771 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc)
772 {
773 uint32_t x, n = 0, add_more = 1;
774 struct sctp_stream_queue_pending *sp;
775 uint16_t i;
776
777 SCTP_TCB_LOCK_ASSERT(stcb);
778
779 TAILQ_INIT(&asoc->ss_data.out.list);
780 /*
781 * If there is data in the stream queues already, the scheduler of
782 * an existing association has been changed. We can only cycle
783 * through the stream queues and add everything to the FCFS queue.
784 */
785 while (add_more) {
786 add_more = 0;
787 for (i = 0; i < asoc->streamoutcnt; i++) {
788 sp = TAILQ_FIRST(&asoc->strmout[i].outqueue);
789 x = 0;
790 /* Find n. message in current stream queue */
791 while (sp != NULL && x < n) {
792 sp = TAILQ_NEXT(sp, next);
793 x++;
794 }
795 if (sp != NULL) {
796 sctp_ss_fcfs_add(stcb, asoc, &asoc->strmout[i], sp);
797 add_more = 1;
798 }
799 }
800 n++;
801 }
802 return;
803 }
804
805 static void
806 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
807 bool clear_values SCTP_UNUSED)
808 {
809 struct sctp_stream_queue_pending *sp;
810
811 SCTP_TCB_LOCK_ASSERT(stcb);
812
813 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
814 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
815 KASSERT(sp->scheduled, ("sp %p not scheduled", (void *)sp));
816 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
817 sp->scheduled = false;
818 }
819 asoc->ss_data.last_out_stream = NULL;
820 return;
821 }
822
823 static void
824 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
825 {
826 SCTP_TCB_LOCK_ASSERT(stcb);
827
828 if (with_strq != NULL) {
829 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
830 stcb->asoc.ss_data.locked_on_sending = strq;
831 }
832 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
833 stcb->asoc.ss_data.last_out_stream = strq;
834 }
835 }
836 strq->ss_params.scheduled = false;
837 return;
838 }
839
840 static void
841 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
842 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp)
843 {
844 SCTP_TCB_LOCK_ASSERT(stcb);
845
846 if (!sp->scheduled) {
847 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
848 sp->scheduled = true;
849 }
850 return;
851 }
852
853 static bool
854 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
855 {
856 SCTP_TCB_LOCK_ASSERT(stcb);
857
858 return (TAILQ_EMPTY(&asoc->ss_data.out.list));
859 }
860
861 static void
862 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
863 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp)
864 {
865 SCTP_TCB_LOCK_ASSERT(stcb);
866
867 if (sp->scheduled) {
868 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
869 sp->scheduled = false;
870 }
871 return;
872 }
873
874 static struct sctp_stream_out *
875 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
876 struct sctp_association *asoc)
877 {
878 struct sctp_stream_out *strq;
879 struct sctp_stream_queue_pending *sp;
880
881 SCTP_TCB_LOCK_ASSERT(stcb);
882
883 if (asoc->ss_data.locked_on_sending) {
884 return (asoc->ss_data.locked_on_sending);
885 }
886 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
887 default_again:
888 if (sp != NULL) {
889 strq = &asoc->strmout[sp->sid];
890 } else {
891 strq = NULL;
892 }
893
894 /*
895 * If CMT is off, we must validate that the stream in question has
896 * the first item pointed towards are network destination requested
897 * by the caller. Note that if we turn out to be locked to a stream
898 * (assigning TSN's then we must stop, since we cannot look for
899 * another stream with data to send to that destination). In CMT's
900 * case, by skipping this check, we will send one data packet
901 * towards the requested net.
902 */
903 if (net != NULL && strq != NULL &&
904 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
905 if (TAILQ_FIRST(&strq->outqueue) &&
906 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
907 TAILQ_FIRST(&strq->outqueue)->net != net) {
908 sp = TAILQ_NEXT(sp, ss_next);
909 goto default_again;
910 }
911 }
912 return (strq);
913 }
914
915 static void
916 sctp_ss_fcfs_scheduled(struct sctp_tcb *stcb,
917 struct sctp_nets *net SCTP_UNUSED,
918 struct sctp_association *asoc,
919 struct sctp_stream_out *strq,
920 int moved_how_much SCTP_UNUSED)
921 {
922 struct sctp_stream_queue_pending *sp;
923
924 KASSERT(strq != NULL, ("strq is NULL"));
925 asoc->ss_data.last_out_stream = strq;
926 if (asoc->idata_supported == 0) {
927 sp = TAILQ_FIRST(&strq->outqueue);
928 if ((sp != NULL) && (sp->some_taken == 1)) {
929 asoc->ss_data.locked_on_sending = strq;
930 } else {
931 asoc->ss_data.locked_on_sending = NULL;
932 }
933 } else {
934 asoc->ss_data.locked_on_sending = NULL;
935 }
936 return;
937 }
938
939 const struct sctp_ss_functions sctp_ss_functions[] = {
940 /* SCTP_SS_DEFAULT */
941 {
942 .sctp_ss_init = sctp_ss_default_init,
943 .sctp_ss_clear = sctp_ss_default_clear,
944 .sctp_ss_init_stream = sctp_ss_default_init_stream,
945 .sctp_ss_add_to_stream = sctp_ss_default_add,
946 .sctp_ss_is_empty = sctp_ss_default_is_empty,
947 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
948 .sctp_ss_select_stream = sctp_ss_default_select,
949 .sctp_ss_scheduled = sctp_ss_default_scheduled,
950 .sctp_ss_packet_done = sctp_ss_default_packet_done,
951 .sctp_ss_get_value = sctp_ss_default_get_value,
952 .sctp_ss_set_value = sctp_ss_default_set_value,
953 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
954 },
955 /* SCTP_SS_ROUND_ROBIN */
956 {
957 .sctp_ss_init = sctp_ss_default_init,
958 .sctp_ss_clear = sctp_ss_default_clear,
959 .sctp_ss_init_stream = sctp_ss_default_init_stream,
960 .sctp_ss_add_to_stream = sctp_ss_rr_add,
961 .sctp_ss_is_empty = sctp_ss_default_is_empty,
962 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
963 .sctp_ss_select_stream = sctp_ss_default_select,
964 .sctp_ss_scheduled = sctp_ss_default_scheduled,
965 .sctp_ss_packet_done = sctp_ss_default_packet_done,
966 .sctp_ss_get_value = sctp_ss_default_get_value,
967 .sctp_ss_set_value = sctp_ss_default_set_value,
968 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
969 },
970 /* SCTP_SS_ROUND_ROBIN_PACKET */
971 {
972 .sctp_ss_init = sctp_ss_default_init,
973 .sctp_ss_clear = sctp_ss_default_clear,
974 .sctp_ss_init_stream = sctp_ss_default_init_stream,
975 .sctp_ss_add_to_stream = sctp_ss_rr_add,
976 .sctp_ss_is_empty = sctp_ss_default_is_empty,
977 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
978 .sctp_ss_select_stream = sctp_ss_rrp_select,
979 .sctp_ss_scheduled = sctp_ss_default_scheduled,
980 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
981 .sctp_ss_get_value = sctp_ss_default_get_value,
982 .sctp_ss_set_value = sctp_ss_default_set_value,
983 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
984 },
985 /* SCTP_SS_PRIORITY */
986 {
987 .sctp_ss_init = sctp_ss_default_init,
988 .sctp_ss_clear = sctp_ss_prio_clear,
989 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
990 .sctp_ss_add_to_stream = sctp_ss_prio_add,
991 .sctp_ss_is_empty = sctp_ss_default_is_empty,
992 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
993 .sctp_ss_select_stream = sctp_ss_prio_select,
994 .sctp_ss_scheduled = sctp_ss_default_scheduled,
995 .sctp_ss_packet_done = sctp_ss_default_packet_done,
996 .sctp_ss_get_value = sctp_ss_prio_get_value,
997 .sctp_ss_set_value = sctp_ss_prio_set_value,
998 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
999 },
1000 /* SCTP_SS_FAIR_BANDWITH */
1001 {
1002 .sctp_ss_init = sctp_ss_default_init,
1003 .sctp_ss_clear = sctp_ss_fb_clear,
1004 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
1005 .sctp_ss_add_to_stream = sctp_ss_fb_add,
1006 .sctp_ss_is_empty = sctp_ss_default_is_empty,
1007 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
1008 .sctp_ss_select_stream = sctp_ss_fb_select,
1009 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
1010 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1011 .sctp_ss_get_value = sctp_ss_default_get_value,
1012 .sctp_ss_set_value = sctp_ss_default_set_value,
1013 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1014 },
1015 /* SCTP_SS_FIRST_COME */
1016 {
1017 .sctp_ss_init = sctp_ss_fcfs_init,
1018 .sctp_ss_clear = sctp_ss_fcfs_clear,
1019 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1020 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1021 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1022 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1023 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1024 .sctp_ss_scheduled = sctp_ss_fcfs_scheduled,
1025 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1026 .sctp_ss_get_value = sctp_ss_default_get_value,
1027 .sctp_ss_set_value = sctp_ss_default_set_value,
1028 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1029 }
1030 };
Cache object: efb1d53c17a31daea8d8c34ab55d11ee
|