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/tcp_sack.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-3-Clause
    3  *
    4  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
    5  *      The Regents of the University of California.
    6  * 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
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)tcp_sack.c  8.12 (Berkeley) 5/24/95
   33  */
   34 
   35 /*-
   36  *      @@(#)COPYRIGHT  1.1 (NRL) 17 January 1995
   37  *
   38  * NRL grants permission for redistribution and use in source and binary
   39  * forms, with or without modification, of the software and documentation
   40  * created at NRL provided that the following conditions are met:
   41  *
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  * 3. All advertising materials mentioning features or use of this software
   48  *    must display the following acknowledgements:
   49  *      This product includes software developed by the University of
   50  *      California, Berkeley and its contributors.
   51  *      This product includes software developed at the Information
   52  *      Technology Division, US Naval Research Laboratory.
   53  * 4. Neither the name of the NRL nor the names of its contributors
   54  *    may be used to endorse or promote products derived from this software
   55  *    without specific prior written permission.
   56  *
   57  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
   58  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   59  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   60  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
   61  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   62  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   63  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   64  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   65  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   66  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   67  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   68  *
   69  * The views and conclusions contained in the software and documentation
   70  * are those of the authors and should not be interpreted as representing
   71  * official policies, either expressed or implied, of the US Naval
   72  * Research Laboratory (NRL).
   73  */
   74 
   75 #include <sys/cdefs.h>
   76 __FBSDID("$FreeBSD$");
   77 
   78 #include "opt_inet.h"
   79 #include "opt_inet6.h"
   80 
   81 #include <sys/param.h>
   82 #include <sys/systm.h>
   83 #include <sys/kernel.h>
   84 #include <sys/sysctl.h>
   85 #include <sys/malloc.h>
   86 #include <sys/mbuf.h>
   87 #include <sys/proc.h>           /* for proc0 declaration */
   88 #include <sys/protosw.h>
   89 #include <sys/socket.h>
   90 #include <sys/socketvar.h>
   91 #include <sys/syslog.h>
   92 #include <sys/systm.h>
   93 
   94 #include <machine/cpu.h>        /* before tcp_seq.h, for tcp_random18() */
   95 
   96 #include <vm/uma.h>
   97 
   98 #include <net/if.h>
   99 #include <net/if_var.h>
  100 #include <net/route.h>
  101 #include <net/vnet.h>
  102 
  103 #include <netinet/in.h>
  104 #include <netinet/in_systm.h>
  105 #include <netinet/ip.h>
  106 #include <netinet/in_var.h>
  107 #include <netinet/in_pcb.h>
  108 #include <netinet/ip_var.h>
  109 #include <netinet/ip6.h>
  110 #include <netinet/icmp6.h>
  111 #include <netinet6/nd6.h>
  112 #include <netinet6/ip6_var.h>
  113 #include <netinet6/in6_pcb.h>
  114 #include <netinet/tcp.h>
  115 #include <netinet/tcp_fsm.h>
  116 #include <netinet/tcp_seq.h>
  117 #include <netinet/tcp_timer.h>
  118 #include <netinet/tcp_var.h>
  119 #include <netinet/tcpip.h>
  120 #include <netinet/cc/cc.h>
  121 
  122 #include <machine/in_cksum.h>
  123 
  124 VNET_DECLARE(struct uma_zone *, sack_hole_zone);
  125 #define V_sack_hole_zone                VNET(sack_hole_zone)
  126 
  127 SYSCTL_NODE(_net_inet_tcp, OID_AUTO, sack, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  128     "TCP SACK");
  129 
  130 VNET_DEFINE(int, tcp_do_sack) = 1;
  131 SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, enable, CTLFLAG_VNET | CTLFLAG_RW,
  132     &VNET_NAME(tcp_do_sack), 0,
  133     "Enable/Disable TCP SACK support");
  134 
  135 VNET_DEFINE(int, tcp_do_newsack) = 1;
  136 SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, revised, CTLFLAG_VNET | CTLFLAG_RW,
  137     &VNET_NAME(tcp_do_newsack), 0,
  138     "Use revised SACK loss recovery per RFC 6675");
  139 
  140 VNET_DEFINE(int, tcp_sack_maxholes) = 128;
  141 SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, maxholes, CTLFLAG_VNET | CTLFLAG_RW,
  142     &VNET_NAME(tcp_sack_maxholes), 0,
  143     "Maximum number of TCP SACK holes allowed per connection");
  144 
  145 VNET_DEFINE(int, tcp_sack_globalmaxholes) = 65536;
  146 SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, globalmaxholes, CTLFLAG_VNET | CTLFLAG_RW,
  147     &VNET_NAME(tcp_sack_globalmaxholes), 0,
  148     "Global maximum number of TCP SACK holes");
  149 
  150 VNET_DEFINE(int, tcp_sack_globalholes) = 0;
  151 SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, globalholes, CTLFLAG_VNET | CTLFLAG_RD,
  152     &VNET_NAME(tcp_sack_globalholes), 0,
  153     "Global number of TCP SACK holes currently allocated");
  154 
  155 int
  156 tcp_dsack_block_exists(struct tcpcb *tp)
  157 {
  158         /* Return true if a DSACK block exists */
  159         if (tp->rcv_numsacks == 0)
  160                 return (0);
  161         if (SEQ_LEQ(tp->sackblks[0].end, tp->rcv_nxt))
  162                 return(1);
  163         return (0);
  164 }
  165 
  166 /*
  167  * This function will find overlaps with the currently stored sackblocks
  168  * and add any overlap as a dsack block upfront
  169  */
  170 void
  171 tcp_update_dsack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
  172 {
  173         struct sackblk head_blk,mid_blk,saved_blks[MAX_SACK_BLKS];
  174         int i, j, n, identical;
  175         tcp_seq start, end;
  176 
  177         INP_WLOCK_ASSERT(tptoinpcb(tp));
  178 
  179         KASSERT(SEQ_LT(rcv_start, rcv_end), ("rcv_start < rcv_end"));
  180 
  181         if (SEQ_LT(rcv_end, tp->rcv_nxt) ||
  182             ((rcv_end == tp->rcv_nxt) &&
  183              (tp->rcv_numsacks > 0 ) &&
  184              (tp->sackblks[0].end == tp->rcv_nxt))) {
  185                 saved_blks[0].start = rcv_start;
  186                 saved_blks[0].end = rcv_end;
  187         } else {
  188                 saved_blks[0].start = saved_blks[0].end = 0;
  189         }
  190 
  191         head_blk.start = head_blk.end = 0;
  192         mid_blk.start = rcv_start;
  193         mid_blk.end = rcv_end;
  194         identical = 0;
  195 
  196         for (i = 0; i < tp->rcv_numsacks; i++) {
  197                 start = tp->sackblks[i].start;
  198                 end = tp->sackblks[i].end;
  199                 if (SEQ_LT(rcv_end, start)) {
  200                         /* pkt left to sack blk */
  201                         continue;
  202                 }
  203                 if (SEQ_GT(rcv_start, end)) {
  204                         /* pkt right to sack blk */
  205                         continue;
  206                 }
  207                 if (SEQ_GT(tp->rcv_nxt, end)) {
  208                         if ((SEQ_MAX(rcv_start, start) != SEQ_MIN(rcv_end, end)) &&
  209                             (SEQ_GT(head_blk.start, SEQ_MAX(rcv_start, start)) ||
  210                             (head_blk.start == head_blk.end))) {
  211                                 head_blk.start = SEQ_MAX(rcv_start, start);
  212                                 head_blk.end = SEQ_MIN(rcv_end, end);
  213                         }
  214                         continue;
  215                 }
  216                 if (((head_blk.start == head_blk.end) ||
  217                      SEQ_LT(start, head_blk.start)) &&
  218                      (SEQ_GT(end, rcv_start) &&
  219                       SEQ_LEQ(start, rcv_end))) {
  220                         head_blk.start = start;
  221                         head_blk.end = end;
  222                 }
  223                 mid_blk.start = SEQ_MIN(mid_blk.start, start);
  224                 mid_blk.end = SEQ_MAX(mid_blk.end, end);
  225                 if ((mid_blk.start == start) &&
  226                     (mid_blk.end == end))
  227                         identical = 1;
  228         }
  229         if (SEQ_LT(head_blk.start, head_blk.end)) {
  230                 /* store overlapping range */
  231                 saved_blks[0].start = SEQ_MAX(rcv_start, head_blk.start);
  232                 saved_blks[0].end   = SEQ_MIN(rcv_end, head_blk.end);
  233         }
  234         n = 1;
  235         /*
  236          * Second, if not ACKed, store the SACK block that
  237          * overlaps with the DSACK block unless it is identical
  238          */
  239         if ((SEQ_LT(tp->rcv_nxt, mid_blk.end) &&
  240             !((mid_blk.start == saved_blks[0].start) &&
  241             (mid_blk.end == saved_blks[0].end))) ||
  242             identical == 1) {
  243                 saved_blks[n].start = mid_blk.start;
  244                 saved_blks[n++].end = mid_blk.end;
  245         }
  246         for (j = 0; (j < tp->rcv_numsacks) && (n < MAX_SACK_BLKS); j++) {
  247                 if (((SEQ_LT(tp->sackblks[j].end, mid_blk.start) ||
  248                       SEQ_GT(tp->sackblks[j].start, mid_blk.end)) &&
  249                     (SEQ_GT(tp->sackblks[j].start, tp->rcv_nxt))))
  250                 saved_blks[n++] = tp->sackblks[j];
  251         }
  252         j = 0;
  253         for (i = 0; i < n; i++) {
  254                 /* we can end up with a stale initial entry */
  255                 if (SEQ_LT(saved_blks[i].start, saved_blks[i].end)) {
  256                         tp->sackblks[j++] = saved_blks[i];
  257                 }
  258         }
  259         tp->rcv_numsacks = j;
  260 }
  261 
  262 /*
  263  * This function is called upon receipt of new valid data (while not in
  264  * header prediction mode), and it updates the ordered list of sacks.
  265  */
  266 void
  267 tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
  268 {
  269         /*
  270          * First reported block MUST be the most recent one.  Subsequent
  271          * blocks SHOULD be in the order in which they arrived at the
  272          * receiver.  These two conditions make the implementation fully
  273          * compliant with RFC 2018.
  274          */
  275         struct sackblk head_blk, saved_blks[MAX_SACK_BLKS];
  276         int num_head, num_saved, i;
  277 
  278         INP_WLOCK_ASSERT(tptoinpcb(tp));
  279 
  280         /* Check arguments. */
  281         KASSERT(SEQ_LEQ(rcv_start, rcv_end), ("rcv_start <= rcv_end"));
  282 
  283         if ((rcv_start == rcv_end) &&
  284             (tp->rcv_numsacks >= 1) &&
  285             (rcv_end == tp->sackblks[0].end)) {
  286                 /* retaining DSACK block below rcv_nxt (todrop) */
  287                 head_blk = tp->sackblks[0];
  288         } else {
  289                 /* SACK block for the received segment. */
  290                 head_blk.start = rcv_start;
  291                 head_blk.end = rcv_end;
  292         }
  293 
  294         /*
  295          * Merge updated SACK blocks into head_blk, and save unchanged SACK
  296          * blocks into saved_blks[].  num_saved will have the number of the
  297          * saved SACK blocks.
  298          */
  299         num_saved = 0;
  300         for (i = 0; i < tp->rcv_numsacks; i++) {
  301                 tcp_seq start = tp->sackblks[i].start;
  302                 tcp_seq end = tp->sackblks[i].end;
  303                 if (SEQ_GEQ(start, end) || SEQ_LEQ(start, tp->rcv_nxt)) {
  304                         /*
  305                          * Discard this SACK block.
  306                          */
  307                 } else if (SEQ_LEQ(head_blk.start, end) &&
  308                            SEQ_GEQ(head_blk.end, start)) {
  309                         /*
  310                          * Merge this SACK block into head_blk.  This SACK
  311                          * block itself will be discarded.
  312                          */
  313                         /*
  314                          * |-|
  315                          *   |---|  merge
  316                          *
  317                          *     |-|
  318                          * |---|    merge
  319                          *
  320                          * |-----|
  321                          *   |-|    DSACK smaller
  322                          *
  323                          *   |-|
  324                          * |-----|  DSACK smaller
  325                          */
  326                         if (head_blk.start == end)
  327                                 head_blk.start = start;
  328                         else if (head_blk.end == start)
  329                                 head_blk.end = end;
  330                         else {
  331                                 if (SEQ_LT(head_blk.start, start)) {
  332                                         tcp_seq temp = start;
  333                                         start = head_blk.start;
  334                                         head_blk.start = temp;
  335                                 }
  336                                 if (SEQ_GT(head_blk.end, end)) {
  337                                         tcp_seq temp = end;
  338                                         end = head_blk.end;
  339                                         head_blk.end = temp;
  340                                 }
  341                                 if ((head_blk.start != start) ||
  342                                     (head_blk.end != end)) {
  343                                         if ((num_saved >= 1) &&
  344                                            SEQ_GEQ(saved_blks[num_saved-1].start, start) &&
  345                                            SEQ_LEQ(saved_blks[num_saved-1].end, end))
  346                                                 num_saved--;
  347                                         saved_blks[num_saved].start = start;
  348                                         saved_blks[num_saved].end = end;
  349                                         num_saved++;
  350                                 }
  351                         }
  352                 } else {
  353                         /*
  354                          * This block supercedes the prior block
  355                          */
  356                         if ((num_saved >= 1) &&
  357                            SEQ_GEQ(saved_blks[num_saved-1].start, start) &&
  358                            SEQ_LEQ(saved_blks[num_saved-1].end, end))
  359                                 num_saved--;
  360                         /*
  361                          * Save this SACK block.
  362                          */
  363                         saved_blks[num_saved].start = start;
  364                         saved_blks[num_saved].end = end;
  365                         num_saved++;
  366                 }
  367         }
  368 
  369         /*
  370          * Update SACK list in tp->sackblks[].
  371          */
  372         num_head = 0;
  373         if (SEQ_LT(rcv_start, rcv_end)) {
  374                 /*
  375                  * The received data segment is an out-of-order segment.  Put
  376                  * head_blk at the top of SACK list.
  377                  */
  378                 tp->sackblks[0] = head_blk;
  379                 num_head = 1;
  380                 /*
  381                  * If the number of saved SACK blocks exceeds its limit,
  382                  * discard the last SACK block.
  383                  */
  384                 if (num_saved >= MAX_SACK_BLKS)
  385                         num_saved--;
  386         }
  387         if ((rcv_start == rcv_end) &&
  388             (rcv_start == tp->sackblks[0].end)) {
  389                 num_head = 1;
  390         }
  391         if (num_saved > 0) {
  392                 /*
  393                  * Copy the saved SACK blocks back.
  394                  */
  395                 bcopy(saved_blks, &tp->sackblks[num_head],
  396                       sizeof(struct sackblk) * num_saved);
  397         }
  398 
  399         /* Save the number of SACK blocks. */
  400         tp->rcv_numsacks = num_head + num_saved;
  401 }
  402 
  403 void
  404 tcp_clean_dsack_blocks(struct tcpcb *tp)
  405 {
  406         struct sackblk saved_blks[MAX_SACK_BLKS];
  407         int num_saved, i;
  408 
  409         INP_WLOCK_ASSERT(tptoinpcb(tp));
  410         /*
  411          * Clean up any DSACK blocks that
  412          * are in our queue of sack blocks.
  413          *
  414          */
  415         num_saved = 0;
  416         for (i = 0; i < tp->rcv_numsacks; i++) {
  417                 tcp_seq start = tp->sackblks[i].start;
  418                 tcp_seq end = tp->sackblks[i].end;
  419                 if (SEQ_GEQ(start, end) || SEQ_LEQ(start, tp->rcv_nxt)) {
  420                         /*
  421                          * Discard this D-SACK block.
  422                          */
  423                         continue;
  424                 }
  425                 /*
  426                  * Save this SACK block.
  427                  */
  428                 saved_blks[num_saved].start = start;
  429                 saved_blks[num_saved].end = end;
  430                 num_saved++;
  431         }
  432         if (num_saved > 0) {
  433                 /*
  434                  * Copy the saved SACK blocks back.
  435                  */
  436                 bcopy(saved_blks, &tp->sackblks[0],
  437                       sizeof(struct sackblk) * num_saved);
  438         }
  439         tp->rcv_numsacks = num_saved;
  440 }
  441 
  442 /*
  443  * Delete all receiver-side SACK information.
  444  */
  445 void
  446 tcp_clean_sackreport(struct tcpcb *tp)
  447 {
  448         int i;
  449 
  450         INP_WLOCK_ASSERT(tptoinpcb(tp));
  451         tp->rcv_numsacks = 0;
  452         for (i = 0; i < MAX_SACK_BLKS; i++)
  453                 tp->sackblks[i].start = tp->sackblks[i].end=0;
  454 }
  455 
  456 /*
  457  * Allocate struct sackhole.
  458  */
  459 static struct sackhole *
  460 tcp_sackhole_alloc(struct tcpcb *tp, tcp_seq start, tcp_seq end)
  461 {
  462         struct sackhole *hole;
  463 
  464         if (tp->snd_numholes >= V_tcp_sack_maxholes ||
  465             V_tcp_sack_globalholes >= V_tcp_sack_globalmaxholes) {
  466                 TCPSTAT_INC(tcps_sack_sboverflow);
  467                 return NULL;
  468         }
  469 
  470         hole = (struct sackhole *)uma_zalloc(V_sack_hole_zone, M_NOWAIT);
  471         if (hole == NULL)
  472                 return NULL;
  473 
  474         hole->start = start;
  475         hole->end = end;
  476         hole->rxmit = start;
  477 
  478         tp->snd_numholes++;
  479         atomic_add_int(&V_tcp_sack_globalholes, 1);
  480 
  481         return hole;
  482 }
  483 
  484 /*
  485  * Free struct sackhole.
  486  */
  487 static void
  488 tcp_sackhole_free(struct tcpcb *tp, struct sackhole *hole)
  489 {
  490 
  491         uma_zfree(V_sack_hole_zone, hole);
  492 
  493         tp->snd_numholes--;
  494         atomic_subtract_int(&V_tcp_sack_globalholes, 1);
  495 
  496         KASSERT(tp->snd_numholes >= 0, ("tp->snd_numholes >= 0"));
  497         KASSERT(V_tcp_sack_globalholes >= 0, ("tcp_sack_globalholes >= 0"));
  498 }
  499 
  500 /*
  501  * Insert new SACK hole into scoreboard.
  502  */
  503 static struct sackhole *
  504 tcp_sackhole_insert(struct tcpcb *tp, tcp_seq start, tcp_seq end,
  505     struct sackhole *after)
  506 {
  507         struct sackhole *hole;
  508 
  509         /* Allocate a new SACK hole. */
  510         hole = tcp_sackhole_alloc(tp, start, end);
  511         if (hole == NULL)
  512                 return NULL;
  513 
  514         /* Insert the new SACK hole into scoreboard. */
  515         if (after != NULL)
  516                 TAILQ_INSERT_AFTER(&tp->snd_holes, after, hole, scblink);
  517         else
  518                 TAILQ_INSERT_TAIL(&tp->snd_holes, hole, scblink);
  519 
  520         /* Update SACK hint. */
  521         if (tp->sackhint.nexthole == NULL)
  522                 tp->sackhint.nexthole = hole;
  523 
  524         return hole;
  525 }
  526 
  527 /*
  528  * Remove SACK hole from scoreboard.
  529  */
  530 static void
  531 tcp_sackhole_remove(struct tcpcb *tp, struct sackhole *hole)
  532 {
  533 
  534         /* Update SACK hint. */
  535         if (tp->sackhint.nexthole == hole)
  536                 tp->sackhint.nexthole = TAILQ_NEXT(hole, scblink);
  537 
  538         /* Remove this SACK hole. */
  539         TAILQ_REMOVE(&tp->snd_holes, hole, scblink);
  540 
  541         /* Free this SACK hole. */
  542         tcp_sackhole_free(tp, hole);
  543 }
  544 
  545 /*
  546  * Process cumulative ACK and the TCP SACK option to update the scoreboard.
  547  * tp->snd_holes is an ordered list of holes (oldest to newest, in terms of
  548  * the sequence space).
  549  * Returns 1 if incoming ACK has previously unknown SACK information,
  550  * 0 otherwise.
  551  */
  552 int
  553 tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
  554 {
  555         struct sackhole *cur, *temp;
  556         struct sackblk sack, sack_blocks[TCP_MAX_SACK + 1], *sblkp;
  557         int i, j, num_sack_blks, sack_changed;
  558         int delivered_data, left_edge_delta;
  559 
  560         INP_WLOCK_ASSERT(tptoinpcb(tp));
  561 
  562         num_sack_blks = 0;
  563         sack_changed = 0;
  564         delivered_data = 0;
  565         left_edge_delta = 0;
  566         /*
  567          * If SND.UNA will be advanced by SEG.ACK, and if SACK holes exist,
  568          * treat [SND.UNA, SEG.ACK) as if it is a SACK block.
  569          * Account changes to SND.UNA always in delivered data.
  570          */
  571         if (SEQ_LT(tp->snd_una, th_ack) && !TAILQ_EMPTY(&tp->snd_holes)) {
  572                 left_edge_delta = th_ack - tp->snd_una;
  573                 sack_blocks[num_sack_blks].start = tp->snd_una;
  574                 sack_blocks[num_sack_blks++].end = th_ack;
  575                 /*
  576                  * Pulling snd_fack forward if we got here
  577                  * due to DSACK blocks
  578                  */
  579                 if (SEQ_LT(tp->snd_fack, th_ack)) {
  580                         delivered_data += th_ack - tp->snd_una;
  581                         tp->snd_fack = th_ack;
  582                         sack_changed = 1;
  583                 }
  584         }
  585         /*
  586          * Append received valid SACK blocks to sack_blocks[], but only if we
  587          * received new blocks from the other side.
  588          */
  589         if (to->to_flags & TOF_SACK) {
  590                 for (i = 0; i < to->to_nsacks; i++) {
  591                         bcopy((to->to_sacks + i * TCPOLEN_SACK),
  592                             &sack, sizeof(sack));
  593                         sack.start = ntohl(sack.start);
  594                         sack.end = ntohl(sack.end);
  595                         if (SEQ_GT(sack.end, sack.start) &&
  596                             SEQ_GT(sack.start, tp->snd_una) &&
  597                             SEQ_GT(sack.start, th_ack) &&
  598                             SEQ_LT(sack.start, tp->snd_max) &&
  599                             SEQ_GT(sack.end, tp->snd_una) &&
  600                             SEQ_LEQ(sack.end, tp->snd_max)) {
  601                                 sack_blocks[num_sack_blks++] = sack;
  602                         } else if (SEQ_LEQ(sack.start, th_ack) &&
  603                             SEQ_LEQ(sack.end, th_ack)) {
  604                                 /*
  605                                  * Its a D-SACK block.
  606                                  */
  607                                 tcp_record_dsack(tp, sack.start, sack.end, 0);
  608                         }
  609                 }
  610         }
  611         /*
  612          * Return if SND.UNA is not advanced and no valid SACK block is
  613          * received.
  614          */
  615         if (num_sack_blks == 0)
  616                 return (sack_changed);
  617 
  618         /*
  619          * Sort the SACK blocks so we can update the scoreboard with just one
  620          * pass. The overhead of sorting up to 4+1 elements is less than
  621          * making up to 4+1 passes over the scoreboard.
  622          */
  623         for (i = 0; i < num_sack_blks; i++) {
  624                 for (j = i + 1; j < num_sack_blks; j++) {
  625                         if (SEQ_GT(sack_blocks[i].end, sack_blocks[j].end)) {
  626                                 sack = sack_blocks[i];
  627                                 sack_blocks[i] = sack_blocks[j];
  628                                 sack_blocks[j] = sack;
  629                         }
  630                 }
  631         }
  632         if (TAILQ_EMPTY(&tp->snd_holes)) {
  633                 /*
  634                  * Empty scoreboard. Need to initialize snd_fack (it may be
  635                  * uninitialized or have a bogus value). Scoreboard holes
  636                  * (from the sack blocks received) are created later below
  637                  * (in the logic that adds holes to the tail of the
  638                  * scoreboard).
  639                  */
  640                 tp->snd_fack = SEQ_MAX(tp->snd_una, th_ack);
  641                 tp->sackhint.sacked_bytes = 0;  /* reset */
  642         }
  643         /*
  644          * In the while-loop below, incoming SACK blocks (sack_blocks[]) and
  645          * SACK holes (snd_holes) are traversed from their tails with just
  646          * one pass in order to reduce the number of compares especially when
  647          * the bandwidth-delay product is large.
  648          *
  649          * Note: Typically, in the first RTT of SACK recovery, the highest
  650          * three or four SACK blocks with the same ack number are received.
  651          * In the second RTT, if retransmitted data segments are not lost,
  652          * the highest three or four SACK blocks with ack number advancing
  653          * are received.
  654          */
  655         sblkp = &sack_blocks[num_sack_blks - 1];        /* Last SACK block */
  656         tp->sackhint.last_sack_ack = sblkp->end;
  657         if (SEQ_LT(tp->snd_fack, sblkp->start)) {
  658                 /*
  659                  * The highest SACK block is beyond fack.  First,
  660                  * check if there was a successful Rescue Retransmission,
  661                  * and move this hole left. With normal holes, snd_fack
  662                  * is always to the right of the end.
  663                  */
  664                 if (((temp = TAILQ_LAST(&tp->snd_holes, sackhole_head)) != NULL) &&
  665                     SEQ_LEQ(tp->snd_fack,temp->end)) {
  666                         temp->start = SEQ_MAX(tp->snd_fack, SEQ_MAX(tp->snd_una, th_ack));
  667                         temp->end = sblkp->start;
  668                         temp->rxmit = temp->start;
  669                         delivered_data += sblkp->end - sblkp->start;
  670                         tp->snd_fack = sblkp->end;
  671                         sblkp--;
  672                         sack_changed = 1;
  673                 } else {
  674                         /*
  675                          * Append a new SACK hole at the tail.  If the
  676                          * second or later highest SACK blocks are also
  677                          * beyond the current fack, they will be inserted
  678                          * by way of hole splitting in the while-loop below.
  679                          */
  680                         temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL);
  681                         if (temp != NULL) {
  682                                 delivered_data += sblkp->end - sblkp->start;
  683                                 tp->snd_fack = sblkp->end;
  684                                 /* Go to the previous sack block. */
  685                                 sblkp--;
  686                                 sack_changed = 1;
  687                         } else {
  688                                 /*
  689                                  * We failed to add a new hole based on the current
  690                                  * sack block.  Skip over all the sack blocks that
  691                                  * fall completely to the right of snd_fack and
  692                                  * proceed to trim the scoreboard based on the
  693                                  * remaining sack blocks.  This also trims the
  694                                  * scoreboard for th_ack (which is sack_blocks[0]).
  695                                  */
  696                                 while (sblkp >= sack_blocks &&
  697                                        SEQ_LT(tp->snd_fack, sblkp->start))
  698                                         sblkp--;
  699                                 if (sblkp >= sack_blocks &&
  700                                     SEQ_LT(tp->snd_fack, sblkp->end)) {
  701                                         delivered_data += sblkp->end - tp->snd_fack;
  702                                         tp->snd_fack = sblkp->end;
  703                                         sack_changed = 1;
  704                                 }
  705                         }
  706                 }
  707         } else if (SEQ_LT(tp->snd_fack, sblkp->end)) {
  708                 /* fack is advanced. */
  709                 delivered_data += sblkp->end - tp->snd_fack;
  710                 tp->snd_fack = sblkp->end;
  711                 sack_changed = 1;
  712         }
  713         cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole. */
  714         /*
  715          * Since the incoming sack blocks are sorted, we can process them
  716          * making one sweep of the scoreboard.
  717          */
  718         while (sblkp >= sack_blocks  && cur != NULL) {
  719                 if (SEQ_GEQ(sblkp->start, cur->end)) {
  720                         /*
  721                          * SACKs data beyond the current hole.  Go to the
  722                          * previous sack block.
  723                          */
  724                         sblkp--;
  725                         continue;
  726                 }
  727                 if (SEQ_LEQ(sblkp->end, cur->start)) {
  728                         /*
  729                          * SACKs data before the current hole.  Go to the
  730                          * previous hole.
  731                          */
  732                         cur = TAILQ_PREV(cur, sackhole_head, scblink);
  733                         continue;
  734                 }
  735                 tp->sackhint.sack_bytes_rexmit -=
  736                     (SEQ_MIN(cur->rxmit, cur->end) - cur->start);
  737                 KASSERT(tp->sackhint.sack_bytes_rexmit >= 0,
  738                     ("sackhint bytes rtx >= 0"));
  739                 sack_changed = 1;
  740                 if (SEQ_LEQ(sblkp->start, cur->start)) {
  741                         /* Data acks at least the beginning of hole. */
  742                         if (SEQ_GEQ(sblkp->end, cur->end)) {
  743                                 /* Acks entire hole, so delete hole. */
  744                                 delivered_data += (cur->end - cur->start);
  745                                 temp = cur;
  746                                 cur = TAILQ_PREV(cur, sackhole_head, scblink);
  747                                 tcp_sackhole_remove(tp, temp);
  748                                 /*
  749                                  * The sack block may ack all or part of the
  750                                  * next hole too, so continue onto the next
  751                                  * hole.
  752                                  */
  753                                 continue;
  754                         } else {
  755                                 /* Move start of hole forward. */
  756                                 delivered_data += (sblkp->end - cur->start);
  757                                 cur->start = sblkp->end;
  758                                 cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
  759                         }
  760                 } else {
  761                         /* Data acks at least the end of hole. */
  762                         if (SEQ_GEQ(sblkp->end, cur->end)) {
  763                                 /* Move end of hole backward. */
  764                                 delivered_data += (cur->end - sblkp->start);
  765                                 cur->end = sblkp->start;
  766                                 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
  767                                 if ((tp->t_flags & TF_LRD) && SEQ_GEQ(cur->rxmit, cur->end))
  768                                         cur->rxmit = tp->snd_recover;
  769                         } else {
  770                                 /*
  771                                  * ACKs some data in middle of a hole; need
  772                                  * to split current hole
  773                                  */
  774                                 temp = tcp_sackhole_insert(tp, sblkp->end,
  775                                     cur->end, cur);
  776                                 if (temp != NULL) {
  777                                         if (SEQ_GT(cur->rxmit, temp->rxmit)) {
  778                                                 temp->rxmit = cur->rxmit;
  779                                                 tp->sackhint.sack_bytes_rexmit +=
  780                                                     (SEQ_MIN(temp->rxmit,
  781                                                     temp->end) - temp->start);
  782                                         }
  783                                         cur->end = sblkp->start;
  784                                         cur->rxmit = SEQ_MIN(cur->rxmit,
  785                                             cur->end);
  786                                         if ((tp->t_flags & TF_LRD) && SEQ_GEQ(cur->rxmit, cur->end))
  787                                                 cur->rxmit = tp->snd_recover;
  788                                         delivered_data += (sblkp->end - sblkp->start);
  789                                 }
  790                         }
  791                 }
  792                 tp->sackhint.sack_bytes_rexmit +=
  793                     (SEQ_MIN(cur->rxmit, cur->end) - cur->start);
  794                 /*
  795                  * Testing sblkp->start against cur->start tells us whether
  796                  * we're done with the sack block or the sack hole.
  797                  * Accordingly, we advance one or the other.
  798                  */
  799                 if (SEQ_LEQ(sblkp->start, cur->start))
  800                         cur = TAILQ_PREV(cur, sackhole_head, scblink);
  801                 else
  802                         sblkp--;
  803         }
  804         if (!(to->to_flags & TOF_SACK))
  805                 /*
  806                  * If this ACK did not contain any
  807                  * SACK blocks, any only moved the
  808                  * left edge right, it is a pure
  809                  * cumulative ACK. Do not count
  810                  * DupAck for this. Also required
  811                  * for RFC6675 rescue retransmission.
  812                  */
  813                 sack_changed = 0;
  814         tp->sackhint.delivered_data = delivered_data;
  815         tp->sackhint.sacked_bytes += delivered_data - left_edge_delta;
  816         KASSERT((delivered_data >= 0), ("delivered_data < 0"));
  817         KASSERT((tp->sackhint.sacked_bytes >= 0), ("sacked_bytes < 0"));
  818         return (sack_changed);
  819 }
  820 
  821 /*
  822  * Free all SACK holes to clear the scoreboard.
  823  */
  824 void
  825 tcp_free_sackholes(struct tcpcb *tp)
  826 {
  827         struct sackhole *q;
  828 
  829         INP_WLOCK_ASSERT(tptoinpcb(tp));
  830         while ((q = TAILQ_FIRST(&tp->snd_holes)) != NULL)
  831                 tcp_sackhole_remove(tp, q);
  832         tp->sackhint.sack_bytes_rexmit = 0;
  833 
  834         KASSERT(tp->snd_numholes == 0, ("tp->snd_numholes == 0"));
  835         KASSERT(tp->sackhint.nexthole == NULL,
  836                 ("tp->sackhint.nexthole == NULL"));
  837 }
  838 
  839 /*
  840  * Partial ack handling within a sack recovery episode.  Keeping this very
  841  * simple for now.  When a partial ack is received, force snd_cwnd to a value
  842  * that will allow the sender to transmit no more than 2 segments.  If
  843  * necessary, a better scheme can be adopted at a later point, but for now,
  844  * the goal is to prevent the sender from bursting a large amount of data in
  845  * the midst of sack recovery.
  846  */
  847 void
  848 tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th)
  849 {
  850         int num_segs = 1;
  851         u_int maxseg = tcp_maxseg(tp);
  852 
  853         INP_WLOCK_ASSERT(tptoinpcb(tp));
  854         tcp_timer_activate(tp, TT_REXMT, 0);
  855         tp->t_rtttime = 0;
  856         /* Send one or 2 segments based on how much new data was acked. */
  857         if ((BYTES_THIS_ACK(tp, th) / maxseg) >= 2)
  858                 num_segs = 2;
  859         tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit +
  860             (tp->snd_nxt - tp->snd_recover) + num_segs * maxseg);
  861         if (tp->snd_cwnd > tp->snd_ssthresh)
  862                 tp->snd_cwnd = tp->snd_ssthresh;
  863         tp->t_flags |= TF_ACKNOW;
  864         /*
  865          * RFC6675 rescue retransmission
  866          * Add a hole between th_ack (snd_una is not yet set) and snd_max,
  867          * if this was a pure cumulative ACK and no data was send beyond
  868          * recovery point. Since the data in the socket has not been freed
  869          * at this point, we check if the scoreboard is empty, and the ACK
  870          * delivered some new data, indicating a full ACK. Also, if the
  871          * recovery point is still at snd_max, we are probably application
  872          * limited. However, this inference might not always be true. The
  873          * rescue retransmission may rarely be slightly premature
  874          * compared to RFC6675.
  875          * The corresponding ACK+SACK will cause any further outstanding
  876          * segments to be retransmitted. This addresses a corner case, when
  877          * the trailing packets of a window are lost and no further data
  878          * is available for sending.
  879          */
  880         if ((V_tcp_do_newsack) &&
  881             SEQ_LT(th->th_ack, tp->snd_recover) &&
  882             (tp->snd_recover == tp->snd_max) &&
  883             TAILQ_EMPTY(&tp->snd_holes) &&
  884             (tp->sackhint.delivered_data > 0)) {
  885                 /*
  886                  * Exclude FIN sequence space in
  887                  * the hole for the rescue retransmission,
  888                  * and also don't create a hole, if only
  889                  * the ACK for a FIN is outstanding.
  890                  */
  891                 tcp_seq highdata = tp->snd_max;
  892                 if (tp->t_flags & TF_SENTFIN)
  893                         highdata--;
  894                 if (th->th_ack != highdata) {
  895                         tp->snd_fack = th->th_ack;
  896                         (void)tcp_sackhole_insert(tp, SEQ_MAX(th->th_ack,
  897                             highdata - maxseg), highdata, NULL);
  898                 }
  899         }
  900         (void) tcp_output(tp);
  901 }
  902 
  903 #if 0
  904 /*
  905  * Debug version of tcp_sack_output() that walks the scoreboard.  Used for
  906  * now to sanity check the hint.
  907  */
  908 static struct sackhole *
  909 tcp_sack_output_debug(struct tcpcb *tp, int *sack_bytes_rexmt)
  910 {
  911         struct sackhole *p;
  912 
  913         INP_WLOCK_ASSERT(tptoinpcb(tp));
  914         *sack_bytes_rexmt = 0;
  915         TAILQ_FOREACH(p, &tp->snd_holes, scblink) {
  916                 if (SEQ_LT(p->rxmit, p->end)) {
  917                         if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */
  918                                 continue;
  919                         }
  920                         *sack_bytes_rexmt += (p->rxmit - p->start);
  921                         break;
  922                 }
  923                 *sack_bytes_rexmt += (SEQ_MIN(p->rxmit, p->end) - p->start);
  924         }
  925         return (p);
  926 }
  927 #endif
  928 
  929 /*
  930  * Returns the next hole to retransmit and the number of retransmitted bytes
  931  * from the scoreboard.  We store both the next hole and the number of
  932  * retransmitted bytes as hints (and recompute these on the fly upon SACK/ACK
  933  * reception).  This avoids scoreboard traversals completely.
  934  *
  935  * The loop here will traverse *at most* one link.  Here's the argument.  For
  936  * the loop to traverse more than 1 link before finding the next hole to
  937  * retransmit, we would need to have at least 1 node following the current
  938  * hint with (rxmit == end).  But, for all holes following the current hint,
  939  * (start == rxmit), since we have not yet retransmitted from them.
  940  * Therefore, in order to traverse more 1 link in the loop below, we need to
  941  * have at least one node following the current hint with (start == rxmit ==
  942  * end).  But that can't happen, (start == end) means that all the data in
  943  * that hole has been sacked, in which case, the hole would have been removed
  944  * from the scoreboard.
  945  */
  946 struct sackhole *
  947 tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt)
  948 {
  949         struct sackhole *hole = NULL;
  950 
  951         INP_WLOCK_ASSERT(tptoinpcb(tp));
  952         *sack_bytes_rexmt = tp->sackhint.sack_bytes_rexmit;
  953         hole = tp->sackhint.nexthole;
  954         if (hole == NULL)
  955                 return (hole);
  956         if (SEQ_GEQ(hole->rxmit, hole->end)) {
  957                 for (;;) {
  958                         hole = TAILQ_NEXT(hole, scblink);
  959                         if (hole == NULL)
  960                                 return (hole);
  961                         if (SEQ_LT(hole->rxmit, hole->end)) {
  962                                 tp->sackhint.nexthole = hole;
  963                                 break;
  964                         }
  965                 }
  966         }
  967         KASSERT(SEQ_LT(hole->start, hole->end), ("%s: hole.start >= hole.end", __func__));
  968         if (!(V_tcp_do_newsack)) {
  969                 KASSERT(SEQ_LT(hole->start, tp->snd_fack), ("%s: hole.start >= snd.fack", __func__));
  970                 KASSERT(SEQ_LT(hole->end, tp->snd_fack), ("%s: hole.end >= snd.fack", __func__));
  971                 KASSERT(SEQ_LT(hole->rxmit, tp->snd_fack), ("%s: hole.rxmit >= snd.fack", __func__));
  972                 if (SEQ_GEQ(hole->start, hole->end) ||
  973                     SEQ_GEQ(hole->start, tp->snd_fack) ||
  974                     SEQ_GEQ(hole->end, tp->snd_fack) ||
  975                     SEQ_GEQ(hole->rxmit, tp->snd_fack)) {
  976                         log(LOG_CRIT,"tcp: invalid SACK hole (%u-%u,%u) vs fwd ack %u, ignoring.\n",
  977                                         hole->start, hole->end, hole->rxmit, tp->snd_fack);
  978                         return (NULL);
  979                 }
  980         }
  981         return (hole);
  982 }
  983 
  984 /*
  985  * After a timeout, the SACK list may be rebuilt.  This SACK information
  986  * should be used to avoid retransmitting SACKed data.  This function
  987  * traverses the SACK list to see if snd_nxt should be moved forward.
  988  */
  989 void
  990 tcp_sack_adjust(struct tcpcb *tp)
  991 {
  992         struct sackhole *p, *cur = TAILQ_FIRST(&tp->snd_holes);
  993 
  994         INP_WLOCK_ASSERT(tptoinpcb(tp));
  995         if (cur == NULL)
  996                 return; /* No holes */
  997         if (SEQ_GEQ(tp->snd_nxt, tp->snd_fack))
  998                 return; /* We're already beyond any SACKed blocks */
  999         /*-
 1000          * Two cases for which we want to advance snd_nxt:
 1001          * i) snd_nxt lies between end of one hole and beginning of another
 1002          * ii) snd_nxt lies between end of last hole and snd_fack
 1003          */
 1004         while ((p = TAILQ_NEXT(cur, scblink)) != NULL) {
 1005                 if (SEQ_LT(tp->snd_nxt, cur->end))
 1006                         return;
 1007                 if (SEQ_GEQ(tp->snd_nxt, p->start))
 1008                         cur = p;
 1009                 else {
 1010                         tp->snd_nxt = p->start;
 1011                         return;
 1012                 }
 1013         }
 1014         if (SEQ_LT(tp->snd_nxt, cur->end))
 1015                 return;
 1016         tp->snd_nxt = tp->snd_fack;
 1017 }
 1018 
 1019 /*
 1020  * Lost Retransmission Detection
 1021  * Check is FACK is beyond the rexmit of the leftmost hole.
 1022  * If yes, we restart sending from still existing holes,
 1023  * and adjust cwnd via the congestion control module.
 1024  */
 1025 void
 1026 tcp_sack_lost_retransmission(struct tcpcb *tp, struct tcphdr *th)
 1027 {
 1028         struct sackhole *temp;
 1029 
 1030         if (IN_RECOVERY(tp->t_flags) &&
 1031             SEQ_GT(tp->snd_fack, tp->snd_recover) &&
 1032             ((temp = TAILQ_FIRST(&tp->snd_holes)) != NULL) &&
 1033             SEQ_GEQ(temp->rxmit, temp->end) &&
 1034             SEQ_GEQ(tp->snd_fack, temp->rxmit)) {
 1035                 TCPSTAT_INC(tcps_sack_lostrexmt);
 1036                 /*
 1037                  * Start retransmissions from the first hole, and
 1038                  * subsequently all other remaining holes, including
 1039                  * those, which had been sent completely before.
 1040                  */
 1041                 tp->sackhint.nexthole = temp;
 1042                 TAILQ_FOREACH(temp, &tp->snd_holes, scblink) {
 1043                         if (SEQ_GEQ(tp->snd_fack, temp->rxmit) &&
 1044                             SEQ_GEQ(temp->rxmit, temp->end))
 1045                                 temp->rxmit = temp->start;
 1046                 }
 1047                 /*
 1048                  * Remember the old ssthresh, to deduct the beta factor used
 1049                  * by the CC module. Finally, set cwnd to ssthresh just
 1050                  * prior to invoking another cwnd reduction by the CC
 1051                  * module, to not shrink it excessively.
 1052                  */
 1053                 tp->snd_cwnd = tp->snd_ssthresh;
 1054                 /*
 1055                  * Formally exit recovery, and let the CC module adjust
 1056                  * ssthresh as intended.
 1057                  */
 1058                 EXIT_RECOVERY(tp->t_flags);
 1059                 cc_cong_signal(tp, th, CC_NDUPACK);
 1060                 /*
 1061                  * For PRR, adjust recover_fs as if this new reduction
 1062                  * initialized this variable.
 1063                  * cwnd will be adjusted by SACK or PRR processing
 1064                  * subsequently, only set it to a safe value here.
 1065                  */
 1066                 tp->snd_cwnd = tcp_maxseg(tp);
 1067                 tp->sackhint.recover_fs = (tp->snd_max - tp->snd_una) -
 1068                                             tp->sackhint.recover_fs;
 1069         }
 1070 }

Cache object: fb09a9c3d7458bdd5a94cf21e9102a72


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