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 }; 1031