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