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