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

Cache object: d08c9ee8a6a479614ce225ceedccbe77


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