sctp_ss_functions.c (34971B)
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, 61 * the scheduler of an existing association has 62 * been changed. We need to add all stream queues 63 * to the wheel. 64 */ 65 for (i = 0; i < asoc->streamoutcnt; i++) { 66 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, 67 &asoc->strmout[i], 68 NULL); 69 } 70 return; 71 } 72 73 static void 74 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, 75 bool clear_values SCTP_UNUSED) 76 { 77 SCTP_TCB_LOCK_ASSERT(stcb); 78 79 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { 80 struct sctp_stream_out *strq; 81 82 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); 83 KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); 84 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); 85 strq->ss_params.scheduled = false; 86 } 87 asoc->ss_data.last_out_stream = NULL; 88 return; 89 } 90 91 static void 92 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) 93 { 94 SCTP_TCB_LOCK_ASSERT(stcb); 95 96 if (with_strq != NULL) { 97 if (stcb->asoc.ss_data.locked_on_sending == with_strq) { 98 stcb->asoc.ss_data.locked_on_sending = strq; 99 } 100 if (stcb->asoc.ss_data.last_out_stream == with_strq) { 101 stcb->asoc.ss_data.last_out_stream = strq; 102 } 103 } 104 strq->ss_params.scheduled = false; 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) 112 { 113 SCTP_TCB_LOCK_ASSERT(stcb); 114 115 /* Add to wheel if not already on it and stream queue not empty */ 116 if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { 117 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, 118 strq, ss_params.ss.rr.next_spoke); 119 strq->ss_params.scheduled = true; 120 } 121 return; 122 } 123 124 static bool 125 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) 126 { 127 SCTP_TCB_LOCK_ASSERT(stcb); 128 129 return (TAILQ_EMPTY(&asoc->ss_data.out.wheel)); 130 } 131 132 static void 133 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, 134 struct sctp_stream_out *strq, 135 struct sctp_stream_queue_pending *sp SCTP_UNUSED) 136 { 137 SCTP_TCB_LOCK_ASSERT(stcb); 138 139 /* Remove from wheel if stream queue is empty and actually is on the wheel */ 140 if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) { 141 if (asoc->ss_data.last_out_stream == strq) { 142 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, 143 sctpwheel_listhead, 144 ss_params.ss.rr.next_spoke); 145 if (asoc->ss_data.last_out_stream == NULL) { 146 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, 147 sctpwheel_listhead); 148 } 149 if (asoc->ss_data.last_out_stream == strq) { 150 asoc->ss_data.last_out_stream = NULL; 151 } 152 } 153 if (asoc->ss_data.locked_on_sending == strq) { 154 asoc->ss_data.locked_on_sending = NULL; 155 } 156 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke); 157 strq->ss_params.scheduled = false; 158 } 159 return; 160 } 161 162 static struct sctp_stream_out * 163 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, 164 struct sctp_association *asoc) 165 { 166 struct sctp_stream_out *strq, *strqt; 167 168 SCTP_TCB_LOCK_ASSERT(stcb); 169 170 if (asoc->ss_data.locked_on_sending != NULL) { 171 KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, 172 ("locked_on_sending %p not scheduled", 173 (void *)asoc->ss_data.locked_on_sending)); 174 return (asoc->ss_data.locked_on_sending); 175 } 176 strqt = asoc->ss_data.last_out_stream; 177 KASSERT(strqt == NULL || strqt->ss_params.scheduled, 178 ("last_out_stream %p not scheduled", (void *)strqt)); 179 default_again: 180 /* Find the next stream to use */ 181 if (strqt == NULL) { 182 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); 183 } else { 184 strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke); 185 if (strq == NULL) { 186 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); 187 } 188 } 189 KASSERT(strq == NULL || strq->ss_params.scheduled, 190 ("strq %p not scheduled", (void *)strq)); 191 192 /* If CMT is off, we must validate that 193 * the stream in question has the first 194 * item pointed towards are network destination 195 * requested by the caller. Note that if we 196 * turn out to be locked to a stream (assigning 197 * TSN's then we must stop, since we cannot 198 * look for another stream with data to send 199 * to that destination). In CMT's case, by 200 * skipping this check, we will send one 201 * data packet 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 /* If CMT is off, we must validate that 369 * the stream in question has the first 370 * item pointed towards are network destination 371 * requested by the caller. Note that if we 372 * turn out to be locked to a stream (assigning 373 * TSN's then we must stop, since we cannot 374 * look for another stream with data to send 375 * to that destination). In CMT's case, by 376 * skipping this check, we will send one 377 * data packet 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 /* Remove from wheel if stream queue is empty and actually is on the wheel */ 478 if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) { 479 if (asoc->ss_data.last_out_stream == strq) { 480 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, 481 sctpwheel_listhead, 482 ss_params.ss.prio.next_spoke); 483 if (asoc->ss_data.last_out_stream == NULL) { 484 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, 485 sctpwheel_listhead); 486 } 487 if (asoc->ss_data.last_out_stream == strq) { 488 asoc->ss_data.last_out_stream = NULL; 489 } 490 } 491 if (asoc->ss_data.locked_on_sending == strq) { 492 asoc->ss_data.locked_on_sending = NULL; 493 } 494 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke); 495 strq->ss_params.scheduled = false; 496 } 497 return; 498 } 499 500 static struct sctp_stream_out* 501 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, 502 struct sctp_association *asoc) 503 { 504 struct sctp_stream_out *strq, *strqt, *strqn; 505 506 SCTP_TCB_LOCK_ASSERT(stcb); 507 508 if (asoc->ss_data.locked_on_sending != NULL) { 509 KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, 510 ("locked_on_sending %p not scheduled", 511 (void *)asoc->ss_data.locked_on_sending)); 512 return (asoc->ss_data.locked_on_sending); 513 } 514 strqt = asoc->ss_data.last_out_stream; 515 KASSERT(strqt == NULL || strqt->ss_params.scheduled, 516 ("last_out_stream %p not scheduled", (void *)strqt)); 517 prio_again: 518 /* Find the next stream to use */ 519 if (strqt == NULL) { 520 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); 521 } else { 522 strqn = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke); 523 if (strqn != NULL && 524 strqn->ss_params.ss.prio.priority == strqt->ss_params.ss.prio.priority) { 525 strq = strqn; 526 } else { 527 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); 528 } 529 } 530 KASSERT(strq == NULL || strq->ss_params.scheduled, 531 ("strq %p not scheduled", (void *)strq)); 532 533 /* If CMT is off, we must validate that 534 * the stream in question has the first 535 * item pointed towards are network destination 536 * requested by the caller. Note that if we 537 * turn out to be locked to a stream (assigning 538 * TSN's then we must stop, since we cannot 539 * look for another stream with data to send 540 * to that destination). In CMT's case, by 541 * skipping this check, we will send one 542 * data packet towards the requested net. 543 */ 544 if (net != NULL && strq != NULL && 545 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { 546 if (TAILQ_FIRST(&strq->outqueue) && 547 TAILQ_FIRST(&strq->outqueue)->net != NULL && 548 TAILQ_FIRST(&strq->outqueue)->net != net) { 549 if (strq == asoc->ss_data.last_out_stream) { 550 return (NULL); 551 } else { 552 strqt = strq; 553 goto prio_again; 554 } 555 } 556 } 557 return (strq); 558 } 559 560 static int 561 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, 562 struct sctp_stream_out *strq, uint16_t *value) 563 { 564 SCTP_TCB_LOCK_ASSERT(stcb); 565 566 if (strq == NULL) { 567 return (-1); 568 } 569 *value = strq->ss_params.ss.prio.priority; 570 return (1); 571 } 572 573 static int 574 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc, 575 struct sctp_stream_out *strq, uint16_t value) 576 { 577 SCTP_TCB_LOCK_ASSERT(stcb); 578 579 if (strq == NULL) { 580 return (-1); 581 } 582 strq->ss_params.ss.prio.priority = value; 583 sctp_ss_prio_remove(stcb, asoc, strq, NULL); 584 sctp_ss_prio_add(stcb, asoc, strq, NULL); 585 return (1); 586 } 587 588 /* 589 * Fair bandwidth algorithm. 590 * Maintains an equal throughput per stream. 591 */ 592 static void 593 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, 594 bool clear_values) 595 { 596 SCTP_TCB_LOCK_ASSERT(stcb); 597 598 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { 599 struct sctp_stream_out *strq; 600 601 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); 602 KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq)); 603 if (clear_values) { 604 strq->ss_params.ss.fb.rounds = -1; 605 } 606 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); 607 strq->ss_params.scheduled = false; 608 } 609 asoc->ss_data.last_out_stream = NULL; 610 return; 611 } 612 613 static void 614 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) 615 { 616 SCTP_TCB_LOCK_ASSERT(stcb); 617 618 if (with_strq != NULL) { 619 if (stcb->asoc.ss_data.locked_on_sending == with_strq) { 620 stcb->asoc.ss_data.locked_on_sending = strq; 621 } 622 if (stcb->asoc.ss_data.last_out_stream == with_strq) { 623 stcb->asoc.ss_data.last_out_stream = strq; 624 } 625 } 626 strq->ss_params.scheduled = false; 627 if (with_strq != NULL) { 628 strq->ss_params.ss.fb.rounds = with_strq->ss_params.ss.fb.rounds; 629 } else { 630 strq->ss_params.ss.fb.rounds = -1; 631 } 632 return; 633 } 634 635 static void 636 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 637 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) 638 { 639 SCTP_TCB_LOCK_ASSERT(stcb); 640 641 if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { 642 if (strq->ss_params.ss.fb.rounds < 0) 643 strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; 644 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); 645 strq->ss_params.scheduled = true; 646 } 647 return; 648 } 649 650 static void 651 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, 652 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) 653 { 654 SCTP_TCB_LOCK_ASSERT(stcb); 655 656 /* Remove from wheel if stream queue is empty and actually is on the wheel */ 657 if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) { 658 if (asoc->ss_data.last_out_stream == strq) { 659 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, 660 sctpwheel_listhead, 661 ss_params.ss.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 if (asoc->ss_data.locked_on_sending == strq) { 671 asoc->ss_data.locked_on_sending = NULL; 672 } 673 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke); 674 strq->ss_params.scheduled = false; 675 } 676 return; 677 } 678 679 static struct sctp_stream_out* 680 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, 681 struct sctp_association *asoc) 682 { 683 struct sctp_stream_out *strq = NULL, *strqt; 684 685 SCTP_TCB_LOCK_ASSERT(stcb); 686 687 if (asoc->ss_data.locked_on_sending != NULL) { 688 KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, 689 ("locked_on_sending %p not scheduled", 690 (void *)asoc->ss_data.locked_on_sending)); 691 return (asoc->ss_data.locked_on_sending); 692 } 693 if (asoc->ss_data.last_out_stream == NULL || 694 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) { 695 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); 696 } else { 697 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.ss.fb.next_spoke); 698 } 699 do { 700 if ((strqt != NULL) && 701 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) || 702 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 && 703 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) || 704 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL && 705 TAILQ_FIRST(&strqt->outqueue)->net == net))))) { 706 if ((strqt->ss_params.ss.fb.rounds >= 0) && 707 ((strq == NULL) || 708 (strqt->ss_params.ss.fb.rounds < strq->ss_params.ss.fb.rounds))) { 709 strq = strqt; 710 } 711 } 712 if (strqt != NULL) { 713 strqt = TAILQ_NEXT(strqt, ss_params.ss.fb.next_spoke); 714 } else { 715 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); 716 } 717 } while (strqt != strq); 718 return (strq); 719 } 720 721 static void 722 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED, 723 struct sctp_association *asoc, struct sctp_stream_out *strq, 724 int moved_how_much SCTP_UNUSED) 725 { 726 struct sctp_stream_queue_pending *sp; 727 struct sctp_stream_out *strqt; 728 int subtract; 729 730 SCTP_TCB_LOCK_ASSERT(stcb); 731 732 if (asoc->idata_supported == 0) { 733 sp = TAILQ_FIRST(&strq->outqueue); 734 if ((sp != NULL) && (sp->some_taken == 1)) { 735 asoc->ss_data.locked_on_sending = strq; 736 } else { 737 asoc->ss_data.locked_on_sending = NULL; 738 } 739 } else { 740 asoc->ss_data.locked_on_sending = NULL; 741 } 742 subtract = strq->ss_params.ss.fb.rounds; 743 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.ss.fb.next_spoke) { 744 strqt->ss_params.ss.fb.rounds -= subtract; 745 if (strqt->ss_params.ss.fb.rounds < 0) 746 strqt->ss_params.ss.fb.rounds = 0; 747 } 748 if (TAILQ_FIRST(&strq->outqueue)) { 749 strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; 750 } else { 751 strq->ss_params.ss.fb.rounds = -1; 752 } 753 asoc->ss_data.last_out_stream = strq; 754 return; 755 } 756 757 /* 758 * First-come, first-serve algorithm. 759 * Maintains the order provided by the application. 760 */ 761 static void 762 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 763 struct sctp_stream_out *strq SCTP_UNUSED, 764 struct sctp_stream_queue_pending *sp); 765 766 static void 767 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc) 768 { 769 uint32_t x, n = 0, add_more = 1; 770 struct sctp_stream_queue_pending *sp; 771 uint16_t i; 772 773 SCTP_TCB_LOCK_ASSERT(stcb); 774 775 TAILQ_INIT(&asoc->ss_data.out.list); 776 /* 777 * If there is data in the stream queues already, 778 * the scheduler of an existing association has 779 * been changed. We can only cycle through the 780 * stream queues and add everything to the FCFS 781 * 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 894 * the stream in question has the first 895 * item pointed towards are network destination 896 * requested by the caller. Note that if we 897 * turn out to be locked to a stream (assigning 898 * TSN's then we must stop, since we cannot 899 * look for another stream with data to send 900 * to that destination). In CMT's case, by 901 * skipping this check, we will send one 902 * data packet towards the requested net. 903 */ 904 if (net != NULL && strq != NULL && 905 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { 906 if (TAILQ_FIRST(&strq->outqueue) && 907 TAILQ_FIRST(&strq->outqueue)->net != NULL && 908 TAILQ_FIRST(&strq->outqueue)->net != net) { 909 sp = TAILQ_NEXT(sp, ss_next); 910 goto default_again; 911 } 912 } 913 return (strq); 914 } 915 916 static void 917 sctp_ss_fcfs_scheduled(struct sctp_tcb *stcb, 918 struct sctp_nets *net SCTP_UNUSED, 919 struct sctp_association *asoc, 920 struct sctp_stream_out *strq, 921 int moved_how_much SCTP_UNUSED) 922 { 923 struct sctp_stream_queue_pending *sp; 924 925 KASSERT(strq != NULL, ("strq is NULL")); 926 asoc->ss_data.last_out_stream = strq; 927 if (asoc->idata_supported == 0) { 928 sp = TAILQ_FIRST(&strq->outqueue); 929 if ((sp != NULL) && (sp->some_taken == 1)) { 930 asoc->ss_data.locked_on_sending = strq; 931 } else { 932 asoc->ss_data.locked_on_sending = NULL; 933 } 934 } else { 935 asoc->ss_data.locked_on_sending = NULL; 936 } 937 return; 938 } 939 940 const struct sctp_ss_functions sctp_ss_functions[] = { 941 /* SCTP_SS_DEFAULT */ 942 { 943 #if defined(_WIN32) 944 sctp_ss_default_init, 945 sctp_ss_default_clear, 946 sctp_ss_default_init_stream, 947 sctp_ss_default_add, 948 sctp_ss_default_is_empty, 949 sctp_ss_default_remove, 950 sctp_ss_default_select, 951 sctp_ss_default_scheduled, 952 sctp_ss_default_packet_done, 953 sctp_ss_default_get_value, 954 sctp_ss_default_set_value, 955 sctp_ss_default_is_user_msgs_incomplete 956 #else 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_default_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 #endif 970 }, 971 /* SCTP_SS_RR */ 972 { 973 #if defined(_WIN32) 974 sctp_ss_default_init, 975 sctp_ss_default_clear, 976 sctp_ss_default_init_stream, 977 sctp_ss_rr_add, 978 sctp_ss_default_is_empty, 979 sctp_ss_default_remove, 980 sctp_ss_default_select, 981 sctp_ss_default_scheduled, 982 sctp_ss_default_packet_done, 983 sctp_ss_default_get_value, 984 sctp_ss_default_set_value, 985 sctp_ss_default_is_user_msgs_incomplete 986 #else 987 .sctp_ss_init = sctp_ss_default_init, 988 .sctp_ss_clear = sctp_ss_default_clear, 989 .sctp_ss_init_stream = sctp_ss_default_init_stream, 990 .sctp_ss_add_to_stream = sctp_ss_rr_add, 991 .sctp_ss_is_empty = sctp_ss_default_is_empty, 992 .sctp_ss_remove_from_stream = sctp_ss_default_remove, 993 .sctp_ss_select_stream = sctp_ss_default_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_default_get_value, 997 .sctp_ss_set_value = sctp_ss_default_set_value, 998 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 999 #endif 1000 }, 1001 /* SCTP_SS_RR_PKT */ 1002 { 1003 #if defined(_WIN32) 1004 sctp_ss_default_init, 1005 sctp_ss_default_clear, 1006 sctp_ss_default_init_stream, 1007 sctp_ss_rr_add, 1008 sctp_ss_default_is_empty, 1009 sctp_ss_default_remove, 1010 sctp_ss_rrp_select, 1011 sctp_ss_default_scheduled, 1012 sctp_ss_rrp_packet_done, 1013 sctp_ss_default_get_value, 1014 sctp_ss_default_set_value, 1015 sctp_ss_default_is_user_msgs_incomplete 1016 #else 1017 .sctp_ss_init = sctp_ss_default_init, 1018 .sctp_ss_clear = sctp_ss_default_clear, 1019 .sctp_ss_init_stream = sctp_ss_default_init_stream, 1020 .sctp_ss_add_to_stream = sctp_ss_rr_add, 1021 .sctp_ss_is_empty = sctp_ss_default_is_empty, 1022 .sctp_ss_remove_from_stream = sctp_ss_default_remove, 1023 .sctp_ss_select_stream = sctp_ss_rrp_select, 1024 .sctp_ss_scheduled = sctp_ss_default_scheduled, 1025 .sctp_ss_packet_done = sctp_ss_rrp_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 #endif 1030 }, 1031 /* SCTP_SS_PRIO */ 1032 { 1033 #if defined(_WIN32) 1034 sctp_ss_default_init, 1035 sctp_ss_prio_clear, 1036 sctp_ss_prio_init_stream, 1037 sctp_ss_prio_add, 1038 sctp_ss_default_is_empty, 1039 sctp_ss_prio_remove, 1040 sctp_ss_prio_select, 1041 sctp_ss_default_scheduled, 1042 sctp_ss_default_packet_done, 1043 sctp_ss_prio_get_value, 1044 sctp_ss_prio_set_value, 1045 sctp_ss_default_is_user_msgs_incomplete 1046 #else 1047 .sctp_ss_init = sctp_ss_default_init, 1048 .sctp_ss_clear = sctp_ss_prio_clear, 1049 .sctp_ss_init_stream = sctp_ss_prio_init_stream, 1050 .sctp_ss_add_to_stream = sctp_ss_prio_add, 1051 .sctp_ss_is_empty = sctp_ss_default_is_empty, 1052 .sctp_ss_remove_from_stream = sctp_ss_prio_remove, 1053 .sctp_ss_select_stream = sctp_ss_prio_select, 1054 .sctp_ss_scheduled = sctp_ss_default_scheduled, 1055 .sctp_ss_packet_done = sctp_ss_default_packet_done, 1056 .sctp_ss_get_value = sctp_ss_prio_get_value, 1057 .sctp_ss_set_value = sctp_ss_prio_set_value, 1058 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 1059 #endif 1060 }, 1061 /* SCTP_SS_FB */ 1062 { 1063 #if defined(_WIN32) 1064 sctp_ss_default_init, 1065 sctp_ss_fb_clear, 1066 sctp_ss_fb_init_stream, 1067 sctp_ss_fb_add, 1068 sctp_ss_default_is_empty, 1069 sctp_ss_fb_remove, 1070 sctp_ss_fb_select, 1071 sctp_ss_fb_scheduled, 1072 sctp_ss_default_packet_done, 1073 sctp_ss_default_get_value, 1074 sctp_ss_default_set_value, 1075 sctp_ss_default_is_user_msgs_incomplete 1076 #else 1077 .sctp_ss_init = sctp_ss_default_init, 1078 .sctp_ss_clear = sctp_ss_fb_clear, 1079 .sctp_ss_init_stream = sctp_ss_fb_init_stream, 1080 .sctp_ss_add_to_stream = sctp_ss_fb_add, 1081 .sctp_ss_is_empty = sctp_ss_default_is_empty, 1082 .sctp_ss_remove_from_stream = sctp_ss_fb_remove, 1083 .sctp_ss_select_stream = sctp_ss_fb_select, 1084 .sctp_ss_scheduled = sctp_ss_fb_scheduled, 1085 .sctp_ss_packet_done = sctp_ss_default_packet_done, 1086 .sctp_ss_get_value = sctp_ss_default_get_value, 1087 .sctp_ss_set_value = sctp_ss_default_set_value, 1088 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 1089 #endif 1090 }, 1091 /* SCTP_SS_FCFS */ 1092 { 1093 #if defined(_WIN32) 1094 sctp_ss_fcfs_init, 1095 sctp_ss_fcfs_clear, 1096 sctp_ss_fcfs_init_stream, 1097 sctp_ss_fcfs_add, 1098 sctp_ss_fcfs_is_empty, 1099 sctp_ss_fcfs_remove, 1100 sctp_ss_fcfs_select, 1101 sctp_ss_fcfs_scheduled, 1102 sctp_ss_default_packet_done, 1103 sctp_ss_default_get_value, 1104 sctp_ss_default_set_value, 1105 sctp_ss_default_is_user_msgs_incomplete 1106 #else 1107 .sctp_ss_init = sctp_ss_fcfs_init, 1108 .sctp_ss_clear = sctp_ss_fcfs_clear, 1109 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream, 1110 .sctp_ss_add_to_stream = sctp_ss_fcfs_add, 1111 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty, 1112 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove, 1113 .sctp_ss_select_stream = sctp_ss_fcfs_select, 1114 .sctp_ss_scheduled = sctp_ss_fcfs_scheduled, 1115 .sctp_ss_packet_done = sctp_ss_default_packet_done, 1116 .sctp_ss_get_value = sctp_ss_default_get_value, 1117 .sctp_ss_set_value = sctp_ss_default_set_value, 1118 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 1119 #endif 1120 } 1121 };