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  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 4. Neither the name of the University nor the names of its contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      @(#)tcp_sack.c  8.12 (Berkeley) 5/24/95
   30  * $FreeBSD: releng/5.4/sys/netinet/tcp_sack.c 155190 2006-02-01 19:43:36Z cperciva $
   31  */
   32 
   33 /*-
   34  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
   35  *      The Regents of the University of California.  All rights reserved.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1. Redistributions of source code must retain the above copyright
   41  *    notice, this list of conditions and the following disclaimer.
   42  * 2. Redistributions in binary form must reproduce the above copyright
   43  *    notice, this list of conditions and the following disclaimer in the
   44  *    documentation and/or other materials provided with the distribution.
   45  * 3. Neither the name of the University nor the names of its contributors
   46  *    may be used to endorse or promote products derived from this software
   47  *    without specific prior written permission.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   59  * SUCH DAMAGE.
   60  *
   61  *      @@(#)COPYRIGHT  1.1 (NRL) 17 January 1995
   62  *
   63  * NRL grants permission for redistribution and use in source and binary
   64  * forms, with or without modification, of the software and documentation
   65  * created at NRL provided that the following conditions are met:
   66  *
   67  * 1. Redistributions of source code must retain the above copyright
   68  *    notice, this list of conditions and the following disclaimer.
   69  * 2. Redistributions in binary form must reproduce the above copyright
   70  *    notice, this list of conditions and the following disclaimer in the
   71  *    documentation and/or other materials provided with the distribution.
   72  * 3. All advertising materials mentioning features or use of this software
   73  *    must display the following acknowledgements:
   74  *      This product includes software developed by the University of
   75  *      California, Berkeley and its contributors.
   76  *      This product includes software developed at the Information
   77  *      Technology Division, US Naval Research Laboratory.
   78  * 4. Neither the name of the NRL nor the names of its contributors
   79  *    may be used to endorse or promote products derived from this software
   80  *    without specific prior written permission.
   81  *
   82  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
   83  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   84  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   85  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
   86  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   87  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   88  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   89  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   90  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   91  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   92  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   93  *
   94  * The views and conclusions contained in the software and documentation
   95  * are those of the authors and should not be interpreted as representing
   96  * official policies, either expressed or implied, of the US Naval
   97  * Research Laboratory (NRL).
   98  */
   99 #include "opt_inet.h"
  100 #include "opt_inet6.h"
  101 #include "opt_ipsec.h"
  102 #include "opt_tcpdebug.h"
  103 #include "opt_tcp_input.h"
  104 #include "opt_tcp_sack.h"
  105 
  106 #include <sys/param.h>
  107 #include <sys/systm.h>
  108 #include <sys/kernel.h>
  109 #include <sys/sysctl.h>
  110 #include <sys/malloc.h>
  111 #include <sys/mbuf.h>
  112 #include <sys/proc.h>           /* for proc0 declaration */
  113 #include <sys/protosw.h>
  114 #include <sys/socket.h>
  115 #include <sys/socketvar.h>
  116 #include <sys/syslog.h>
  117 #include <sys/systm.h>
  118 
  119 #include <machine/cpu.h>        /* before tcp_seq.h, for tcp_random18() */
  120 
  121 #include <vm/uma.h>
  122 
  123 #include <net/if.h>
  124 #include <net/route.h>
  125 
  126 #include <netinet/in.h>
  127 #include <netinet/in_systm.h>
  128 #include <netinet/ip.h>
  129 #include <netinet/ip_icmp.h>    /* for ICMP_BANDLIM             */
  130 #include <netinet/in_var.h>
  131 #include <netinet/icmp_var.h>   /* for ICMP_BANDLIM             */
  132 #include <netinet/in_pcb.h>
  133 #include <netinet/ip_var.h>
  134 #include <netinet/ip6.h>
  135 #include <netinet/icmp6.h>
  136 #include <netinet6/nd6.h>
  137 #include <netinet6/ip6_var.h>
  138 #include <netinet6/in6_pcb.h>
  139 #include <netinet/tcp.h>
  140 #include <netinet/tcp_fsm.h>
  141 #include <netinet/tcp_seq.h>
  142 #include <netinet/tcp_timer.h>
  143 #include <netinet/tcp_var.h>
  144 #include <netinet6/tcp6_var.h>
  145 #include <netinet/tcpip.h>
  146 #ifdef TCPDEBUG
  147 #include <netinet/tcp_debug.h>
  148 
  149 u_char tcp_saveipgen[40]; /* the size must be of max ip header, now IPv6 */
  150 struct tcphdr tcp_savetcp;
  151 #endif /* TCPDEBUG */
  152 
  153 #ifdef FAST_IPSEC
  154 #include <netipsec/ipsec.h>
  155 #include <netipsec/ipsec6.h>
  156 #endif
  157 
  158 #ifdef IPSEC
  159 #include <netinet6/ipsec.h>
  160 #include <netinet6/ipsec6.h>
  161 #include <netkey/key.h>
  162 #endif /*IPSEC*/
  163 #include <machine/in_cksum.h>
  164 
  165 extern struct uma_zone *sack_hole_zone;
  166 
  167 SYSCTL_NODE(_net_inet_tcp, OID_AUTO, sack, CTLFLAG_RW, 0, "TCP SACK");
  168 int tcp_do_sack = 1;
  169 SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, enable, CTLFLAG_RW,
  170         &tcp_do_sack, 0, "Enable/Disable TCP SACK support");
  171 TUNABLE_INT("net.inet.tcp.sack.enable", &tcp_do_sack);
  172 
  173 /*
  174  * This function is called upon receipt of new valid data (while not in header
  175  * prediction mode), and it updates the ordered list of sacks.
  176  */
  177 void
  178 tcp_update_sack_list(tp, rcv_laststart, rcv_lastend)
  179         struct tcpcb *tp;
  180         tcp_seq rcv_laststart, rcv_lastend;
  181 {
  182         /*
  183          * First reported block MUST be the most recent one.  Subsequent
  184          * blocks SHOULD be in the order in which they arrived at the
  185          * receiver.  These two conditions make the implementation fully
  186          * compliant with RFC 2018.
  187          */
  188         int i, j = 0, count = 0, lastpos = -1;
  189         struct sackblk sack, firstsack, temp[MAX_SACK_BLKS];
  190 
  191         INP_LOCK_ASSERT(tp->t_inpcb);
  192         /* First clean up current list of sacks */
  193         for (i = 0; i < tp->rcv_numsacks; i++) {
  194                 sack = tp->sackblks[i];
  195                 if (sack.start == 0 && sack.end == 0) {
  196                         count++; /* count = number of blocks to be discarded */
  197                         continue;
  198                 }
  199                 if (SEQ_LEQ(sack.end, tp->rcv_nxt)) {
  200                         tp->sackblks[i].start = tp->sackblks[i].end = 0;
  201                         count++;
  202                 } else {
  203                         temp[j].start = tp->sackblks[i].start;
  204                         temp[j++].end = tp->sackblks[i].end;
  205                 }
  206         }
  207         tp->rcv_numsacks -= count;
  208         if (tp->rcv_numsacks == 0) { /* no sack blocks currently (fast path) */
  209                 tcp_clean_sackreport(tp);
  210                 if (SEQ_LT(tp->rcv_nxt, rcv_laststart)) {
  211                         /* ==> need first sack block */
  212                         tp->sackblks[0].start = rcv_laststart;
  213                         tp->sackblks[0].end = rcv_lastend;
  214                         tp->rcv_numsacks = 1;
  215                 }
  216                 return;
  217         }
  218         /* Otherwise, sack blocks are already present. */
  219         for (i = 0; i < tp->rcv_numsacks; i++)
  220                 tp->sackblks[i] = temp[i]; /* first copy back sack list */
  221         if (SEQ_GEQ(tp->rcv_nxt, rcv_lastend))
  222                 return;     /* sack list remains unchanged */
  223         /*
  224          * From here, segment just received should be (part of) the 1st sack.
  225          * Go through list, possibly coalescing sack block entries.
  226          */
  227         firstsack.start = rcv_laststart;
  228         firstsack.end = rcv_lastend;
  229         for (i = 0; i < tp->rcv_numsacks; i++) {
  230                 sack = tp->sackblks[i];
  231                 if (SEQ_LT(sack.end, firstsack.start) ||
  232                     SEQ_GT(sack.start, firstsack.end))
  233                         continue; /* no overlap */
  234                 if (sack.start == firstsack.start && sack.end == firstsack.end){
  235                         /*
  236                          * identical block; delete it here since we will
  237                          * move it to the front of the list.
  238                          */
  239                         tp->sackblks[i].start = tp->sackblks[i].end = 0;
  240                         lastpos = i;    /* last posn with a zero entry */
  241                         continue;
  242                 }
  243                 if (SEQ_LEQ(sack.start, firstsack.start))
  244                         firstsack.start = sack.start; /* merge blocks */
  245                 if (SEQ_GEQ(sack.end, firstsack.end))
  246                         firstsack.end = sack.end;     /* merge blocks */
  247                 tp->sackblks[i].start = tp->sackblks[i].end = 0;
  248                 lastpos = i;    /* last posn with a zero entry */
  249         }
  250         if (lastpos != -1) {    /* at least one merge */
  251                 for (i = 0, j = 1; i < tp->rcv_numsacks; i++) {
  252                         sack = tp->sackblks[i];
  253                         if (sack.start == 0 && sack.end == 0)
  254                                 continue;
  255                         temp[j++] = sack;
  256                 }
  257                 tp->rcv_numsacks = j; /* including first blk (added later) */
  258                 for (i = 1; i < tp->rcv_numsacks; i++) /* now copy back */
  259                         tp->sackblks[i] = temp[i];
  260         } else {        /* no merges -- shift sacks by 1 */
  261                 if (tp->rcv_numsacks < MAX_SACK_BLKS)
  262                         tp->rcv_numsacks++;
  263                 for (i = tp->rcv_numsacks-1; i > 0; i--)
  264                         tp->sackblks[i] = tp->sackblks[i-1];
  265         }
  266         tp->sackblks[0] = firstsack;
  267         return;
  268 }
  269 
  270 /*
  271  * Delete all receiver-side SACK information.
  272  */
  273 void
  274 tcp_clean_sackreport(tp)
  275         struct tcpcb *tp;
  276 {
  277         int i;
  278 
  279         INP_LOCK_ASSERT(tp->t_inpcb);
  280         tp->rcv_numsacks = 0;
  281         for (i = 0; i < MAX_SACK_BLKS; i++)
  282                 tp->sackblks[i].start = tp->sackblks[i].end=0;
  283 }
  284 
  285 /*
  286  * Process the TCP SACK option.  Returns 1 if tcp_dooptions() should continue,
  287  * and 0 otherwise, if the option was fine.  tp->snd_holes is an ordered list
  288  * of holes (oldest to newest, in terms of the sequence space).
  289  */
  290 int
  291 tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
  292 {
  293         int tmp_olen;
  294         u_char *tmp_cp;
  295         struct sackhole *cur, *p, *temp;
  296 
  297         INP_LOCK_ASSERT(tp->t_inpcb);
  298         if (!tp->sack_enable)
  299                 return (1);
  300 
  301         /* Note: TCPOLEN_SACK must be 2*sizeof(tcp_seq) */
  302         if (optlen <= 2 || (optlen - 2) % TCPOLEN_SACK != 0)
  303                 return (1);
  304         tmp_cp = cp + 2;
  305         tmp_olen = optlen - 2;
  306         tcpstat.tcps_sack_rcv_blocks++;
  307         if (tp->snd_numholes < 0)
  308                 tp->snd_numholes = 0;
  309         if (tp->t_maxseg == 0)
  310                 panic("tcp_sack_option"); /* Should never happen */
  311 next_block:
  312         while (tmp_olen > 0) {
  313                 struct sackblk sack;
  314 
  315                 bcopy(tmp_cp, (char *) &(sack.start), sizeof(tcp_seq));
  316                 sack.start = ntohl(sack.start);
  317                 bcopy(tmp_cp + sizeof(tcp_seq),
  318                     (char *) &(sack.end), sizeof(tcp_seq));
  319                 sack.end = ntohl(sack.end);
  320                 tmp_olen -= TCPOLEN_SACK;
  321                 tmp_cp += TCPOLEN_SACK;
  322                 if (SEQ_LEQ(sack.end, sack.start))
  323                         continue; /* bad SACK fields */
  324                 if (SEQ_LEQ(sack.end, tp->snd_una))
  325                         continue; /* old block */
  326                 if (SEQ_GT(th->th_ack, tp->snd_una)) {
  327                         if (SEQ_LT(sack.start, th->th_ack))
  328                                 continue;
  329                 }
  330                 if (SEQ_GT(sack.end, tp->snd_max))
  331                         continue;
  332                 if (tp->snd_holes == NULL) { /* first hole */
  333                         tp->snd_holes = (struct sackhole *)
  334                                 uma_zalloc(sack_hole_zone,M_NOWAIT);
  335                         if (tp->snd_holes == NULL) {
  336                                 /* ENOBUFS, so ignore SACKed block for now*/
  337                                 continue;
  338                         }
  339                         cur = tp->snd_holes;
  340                         cur->start = th->th_ack;
  341                         cur->end = sack.start;
  342                         cur->rxmit = cur->start;
  343                         cur->next = NULL;
  344                         tp->snd_numholes = 1;
  345                         tp->rcv_lastsack = sack.end;
  346                         continue; /* with next sack block */
  347                 }
  348                 /* Go thru list of holes:  p = previous,  cur = current */
  349                 p = cur = tp->snd_holes;
  350                 while (cur) {
  351                         if (SEQ_LEQ(sack.end, cur->start))
  352                                 /* SACKs data before the current hole */
  353                                 break; /* no use going through more holes */
  354                         if (SEQ_GEQ(sack.start, cur->end)) {
  355                                 /* SACKs data beyond the current hole */
  356                                 p = cur;
  357                                 cur = cur->next;
  358                                 continue;
  359                         }
  360                         if (SEQ_LEQ(sack.start, cur->start)) {
  361                                 /* Data acks at least the beginning of hole */
  362                                 if (SEQ_GEQ(sack.end, cur->end)) {
  363                                         /* Acks entire hole, so delete hole */
  364                                         if (p != cur) {
  365                                                 p->next = cur->next;
  366                                                 uma_zfree(sack_hole_zone, cur);
  367                                                 cur = p->next;
  368                                         } else {
  369                                                 cur = cur->next;
  370                                                 uma_zfree(sack_hole_zone, p);
  371                                                 p = cur;
  372                                                 tp->snd_holes = p;
  373                                         }
  374                                         tp->snd_numholes--;
  375                                         continue;
  376                                 }
  377                                 /* otherwise, move start of hole forward */
  378                                 cur->start = sack.end;
  379                                 cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
  380                                 p = cur;
  381                                 cur = cur->next;
  382                                 continue;
  383                         }
  384                         /* move end of hole backward */
  385                         if (SEQ_GEQ(sack.end, cur->end)) {
  386                                 cur->end = sack.start;
  387                                 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
  388                                 p = cur;
  389                                 cur = cur->next;
  390                                 continue;
  391                         }
  392                         if (SEQ_LT(cur->start, sack.start) &&
  393                             SEQ_GT(cur->end, sack.end)) {
  394                                 /*
  395                                  * ACKs some data in middle of a hole; need to
  396                                  * split current hole
  397                                  */
  398                                 temp = (struct sackhole *)
  399                                         uma_zalloc(sack_hole_zone,M_NOWAIT);
  400                                 if (temp == NULL)
  401                                         goto next_block; /* ENOBUFS */
  402                                 temp->next = cur->next;
  403                                 temp->start = sack.end;
  404                                 temp->end = cur->end;
  405                                 temp->rxmit = SEQ_MAX(cur->rxmit, temp->start);
  406                                 cur->end = sack.start;
  407                                 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
  408                                 cur->next = temp;
  409                                 p = temp;
  410                                 cur = p->next;
  411                                 tp->snd_numholes++;
  412                         }
  413                 }
  414                 /* At this point, p points to the last hole on the list */
  415                 if (SEQ_LT(tp->rcv_lastsack, sack.start)) {
  416                         /*
  417                          * Need to append new hole at end.
  418                          * Last hole is p (and it's not NULL).
  419                          */
  420                         temp = (struct sackhole *)
  421                                 uma_zalloc(sack_hole_zone,M_NOWAIT);
  422                         if (temp == NULL)
  423                                 continue; /* ENOBUFS */
  424                         temp->start = tp->rcv_lastsack;
  425                         temp->end = sack.start;
  426                         temp->rxmit = temp->start;
  427                         temp->next = 0;
  428                         p->next = temp;
  429                         tp->rcv_lastsack = sack.end;
  430                         tp->snd_numholes++;
  431                 }
  432         }
  433         return (0);
  434 }
  435 
  436 /*
  437  * Delete stale (i.e, cumulatively ack'd) holes.  Hole is deleted only if
  438  * it is completely acked; otherwise, tcp_sack_option(), called from
  439  * tcp_dooptions(), will fix up the hole.
  440  */
  441 void
  442 tcp_del_sackholes(tp, th)
  443         struct tcpcb *tp;
  444         struct tcphdr *th;
  445 {
  446         INP_LOCK_ASSERT(tp->t_inpcb);
  447         if (tp->sack_enable && tp->t_state != TCPS_LISTEN) {
  448                 /* max because this could be an older ack just arrived */
  449                 tcp_seq lastack = SEQ_GT(th->th_ack, tp->snd_una) ?
  450                         th->th_ack : tp->snd_una;
  451                 struct sackhole *cur = tp->snd_holes;
  452                 struct sackhole *prev;
  453                 while (cur)
  454                         if (SEQ_LEQ(cur->end, lastack)) {
  455                                 prev = cur;
  456                                 cur = cur->next;
  457                                 uma_zfree(sack_hole_zone, prev);
  458                                 tp->snd_numholes--;
  459                         } else if (SEQ_LT(cur->start, lastack)) {
  460                                 cur->start = lastack;
  461                                 if (SEQ_LT(cur->rxmit, cur->start))
  462                                         cur->rxmit = cur->start;
  463                                 break;
  464                         } else
  465                                 break;
  466                 tp->snd_holes = cur;
  467         }
  468 }
  469 
  470 void
  471 tcp_free_sackholes(struct tcpcb *tp)
  472 {
  473         struct sackhole *p, *q;
  474 
  475         INP_LOCK_ASSERT(tp->t_inpcb);
  476         q = tp->snd_holes;
  477         while (q != NULL) {
  478                 p = q;
  479                 q = q->next;
  480                 uma_zfree(sack_hole_zone, p);
  481         }
  482         tp->snd_holes = 0;
  483 }
  484 
  485 /*
  486  * Partial ack handling within a sack recovery episode. 
  487  * Keeping this very simple for now. When a partial ack
  488  * is received, force snd_cwnd to a value that will allow
  489  * the sender to transmit no more than 2 segments.
  490  * If necessary, a better scheme can be adopted at a 
  491  * later point, but for now, the goal is to prevent the
  492  * sender from bursting a large amount of data in the midst
  493  * of sack recovery.
  494  */
  495 void
  496 tcp_sack_partialack(tp, th)
  497         struct tcpcb *tp;
  498         struct tcphdr *th;
  499 {
  500         INP_LOCK_ASSERT(tp->t_inpcb);
  501         int num_segs = 1;
  502         int sack_bytes_rxmt = 0;
  503 
  504         callout_stop(tp->tt_rexmt);
  505         tp->t_rtttime = 0;
  506         /* send one or 2 segments based on how much new data was acked */
  507         if (((th->th_ack - tp->snd_una) / tp->t_maxseg) > 2)
  508                 num_segs = 2;
  509         (void)tcp_sack_output(tp, &sack_bytes_rxmt);
  510         tp->snd_cwnd = sack_bytes_rxmt + (tp->snd_nxt - tp->sack_newdata) +
  511                 num_segs * tp->t_maxseg;
  512         tp->t_flags |= TF_ACKNOW;
  513         (void) tcp_output(tp);
  514 }
  515 
  516 #ifdef TCP_SACK_DEBUG
  517 void
  518 tcp_print_holes(struct tcpcb *tp)
  519 {
  520         struct sackhole *p = tp->snd_holes;
  521         if (p == 0)
  522                 return;
  523         printf("Hole report: start--end dups rxmit\n");
  524         while (p) {
  525                 printf("%x--%x r %x\n", p->start, p->end, p->rxmit);
  526                 p = p->next;
  527         }
  528         printf("\n");
  529 }
  530 #endif /* TCP_SACK_DEBUG */
  531 
  532 /*
  533  * Returns pointer to a sackhole if there are any pending retransmissions;
  534  * NULL otherwise.
  535  */
  536 struct sackhole *
  537 tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt)
  538 {
  539         struct sackhole *p = NULL;
  540 
  541         INP_LOCK_ASSERT(tp->t_inpcb);
  542         if (!tp->sack_enable)
  543                 return (NULL);
  544         *sack_bytes_rexmt = 0;
  545         for (p = tp->snd_holes; p ; p = p->next) {
  546                 if (SEQ_LT(p->rxmit, p->end)) {
  547                         if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */
  548                                 continue;
  549                         }
  550 #ifdef TCP_SACK_DEBUG
  551                         if (p)
  552                                 tcp_print_holes(tp);
  553 #endif
  554                         *sack_bytes_rexmt += (p->rxmit - p->start);
  555                         break;
  556                 }
  557                 *sack_bytes_rexmt += (p->rxmit - p->start);
  558         }
  559         return (p);
  560 }
  561 
  562 /*
  563  * After a timeout, the SACK list may be rebuilt.  This SACK information
  564  * should be used to avoid retransmitting SACKed data.  This function
  565  * traverses the SACK list to see if snd_nxt should be moved forward.
  566  */
  567 void
  568 tcp_sack_adjust(struct tcpcb *tp)
  569 {
  570         INP_LOCK_ASSERT(tp->t_inpcb);
  571         struct sackhole *cur = tp->snd_holes;
  572         if (cur == NULL)
  573                 return; /* No holes */
  574         if (SEQ_GEQ(tp->snd_nxt, tp->rcv_lastsack))
  575                 return; /* We're already beyond any SACKed blocks */
  576         /*
  577          * Two cases for which we want to advance snd_nxt:
  578          * i) snd_nxt lies between end of one hole and beginning of another
  579          * ii) snd_nxt lies between end of last hole and rcv_lastsack
  580          */
  581         while (cur->next) {
  582                 if (SEQ_LT(tp->snd_nxt, cur->end))
  583                         return;
  584                 if (SEQ_GEQ(tp->snd_nxt, cur->next->start))
  585                         cur = cur->next;
  586                 else {
  587                         tp->snd_nxt = cur->next->start;
  588                         return;
  589                 }
  590         }
  591         if (SEQ_LT(tp->snd_nxt, cur->end))
  592                 return;
  593         tp->snd_nxt = tp->rcv_lastsack;
  594         return;
  595 }

Cache object: 6c856619430f9dccd3b55a5661ef5ca4


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