The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/sctp_ss_functions.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3925db97987948afb6b56371306de5cf


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.