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

Cache object: e99ab2d5ca11a7226e3544dbe789b83d


[ 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.