]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/tcp_sack.c
xnu-2422.100.13.tar.gz
[apple/xnu.git] / bsd / netinet / tcp_sack.c
index 0ea4185500e7ed7493a86dfb5caf6d968f1dd0d4..4ca79aeac59da3043d0c014362cc59e23d4c6e8e 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -72,6 +72,8 @@
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 
+#include <kern/zalloc.h>
+
 #include <net/route.h>
 
 #include <netinet/in.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
 #endif /*IPSEC*/
 
 int    tcp_do_sack = 1;
 #endif /*IPSEC*/
 
 int    tcp_do_sack = 1;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack, CTLFLAG_RW, &tcp_do_sack, 0,
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack, CTLFLAG_RW | CTLFLAG_LOCKED, &tcp_do_sack, 0,
        "Enable/Disable TCP SACK support");
 static int tcp_sack_maxholes = 128;
        "Enable/Disable TCP SACK support");
 static int tcp_sack_maxholes = 128;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_maxholes, CTLFLAG_RW,
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_maxholes, CTLFLAG_RW | CTLFLAG_LOCKED,
        &tcp_sack_maxholes, 0, 
     "Maximum number of TCP SACK holes allowed per connection");
 
 static int tcp_sack_globalmaxholes = 65536;
        &tcp_sack_maxholes, 0, 
     "Maximum number of TCP SACK holes allowed per connection");
 
 static int tcp_sack_globalmaxholes = 65536;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_globalmaxholes, CTLFLAG_RW,
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_globalmaxholes, CTLFLAG_RW | CTLFLAG_LOCKED,
        &tcp_sack_globalmaxholes, 0, 
     "Global maximum number of TCP SACK holes");
 
 static int tcp_sack_globalholes = 0;
        &tcp_sack_globalmaxholes, 0, 
     "Global maximum number of TCP SACK holes");
 
 static int tcp_sack_globalholes = 0;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_globalholes, CTLFLAG_RD,
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_globalholes, CTLFLAG_RD | CTLFLAG_LOCKED,
     &tcp_sack_globalholes, 0,
     "Global number of TCP SACK holes currently allocated");
 
     &tcp_sack_globalholes, 0,
     "Global number of TCP SACK holes currently allocated");
 
@@ -201,6 +203,18 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
 
        /* Save the number of SACK blocks. */
        tp->rcv_numsacks = num_head + num_saved;
 
        /* Save the number of SACK blocks. */
        tp->rcv_numsacks = num_head + num_saved;
+
+       /* If we are requesting SACK recovery, reset the stretch-ack state
+        * so that connection will generate more acks after recovery and
+        * sender's cwnd will open.
+        */
+       if ((tp->t_flags & TF_STRETCHACK) != 0 && tp->rcv_numsacks > 0)
+               tcp_reset_stretch_ack(tp);
+
+#if TRAFFIC_MGT
+       if (tp->acc_iaj > 0 && tp->rcv_numsacks > 0) 
+               reset_acc_iaj(tp);
+#endif /* TRAFFIC_MGT */
 }
 
 /*
 }
 
 /*
@@ -209,13 +223,8 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
 void
 tcp_clean_sackreport( struct tcpcb *tp)
 {
 void
 tcp_clean_sackreport( struct tcpcb *tp)
 {
-/*
-       int i;
 
        tp->rcv_numsacks = 0;
 
        tp->rcv_numsacks = 0;
-       for (i = 0; i < MAX_SACK_BLKS; i++)
-               tp->sackblks[i].start = tp->sackblks[i].end=0;
-*/
        bzero(&tp->sackblks[0], sizeof (struct sackblk) * MAX_SACK_BLKS);
 }
 
        bzero(&tp->sackblks[0], sizeof (struct sackblk) * MAX_SACK_BLKS);
 }
 
@@ -309,7 +318,8 @@ tcp_sackhole_remove(struct tcpcb *tp, struct sackhole *hole)
  * the sequence space).
  */
 void
  * the sequence space).
  */
 void
-tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
+tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack, 
+       u_int32_t *newbytes_acked)
 {
        struct sackhole *cur, *temp;
        struct sackblk sack, sack_blocks[TCP_MAX_SACK + 1], *sblkp;
 {
        struct sackhole *cur, *temp;
        struct sackblk sack, sack_blocks[TCP_MAX_SACK + 1], *sblkp;
@@ -326,14 +336,18 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
        }
        /*
         * Append received valid SACK blocks to sack_blocks[].
        }
        /*
         * Append received valid SACK blocks to sack_blocks[].
+        * Check that the SACK block range is valid.
         */
        for (i = 0; i < to->to_nsacks; i++) {
         */
        for (i = 0; i < to->to_nsacks; i++) {
-               bcopy((to->to_sacks + i * TCPOLEN_SACK), &sack, sizeof(sack));
+               bcopy((to->to_sacks + i * TCPOLEN_SACK),
+                   &sack, sizeof(sack));
                sack.start = ntohl(sack.start);
                sack.end = ntohl(sack.end);
                if (SEQ_GT(sack.end, sack.start) &&
                    SEQ_GT(sack.start, tp->snd_una) &&
                    SEQ_GT(sack.start, th_ack) &&
                sack.start = ntohl(sack.start);
                sack.end = ntohl(sack.end);
                if (SEQ_GT(sack.end, sack.start) &&
                    SEQ_GT(sack.start, tp->snd_una) &&
                    SEQ_GT(sack.start, th_ack) &&
+                   SEQ_LT(sack.start, tp->snd_max) &&
+                   SEQ_GT(sack.end, tp->snd_una) &&
                    SEQ_LEQ(sack.end, tp->snd_max))
                        sack_blocks[num_sack_blks++] = sack;
        }
                    SEQ_LEQ(sack.end, tp->snd_max))
                        sack_blocks[num_sack_blks++] = sack;
        }
@@ -359,7 +373,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                        }
                }
        }
                        }
                }
        }
-       if (TAILQ_EMPTY(&tp->snd_holes))
+       if (TAILQ_EMPTY(&tp->snd_holes)) {
                /*
                 * Empty scoreboard. Need to initialize snd_fack (it may be
                 * uninitialized or have a bogus value). Scoreboard holes
                /*
                 * Empty scoreboard. Need to initialize snd_fack (it may be
                 * uninitialized or have a bogus value). Scoreboard holes
@@ -367,6 +381,9 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                 * the logic that adds holes to the tail of the scoreboard).
                 */
                tp->snd_fack = SEQ_MAX(tp->snd_una, th_ack);
                 * the logic that adds holes to the tail of the scoreboard).
                 */
                tp->snd_fack = SEQ_MAX(tp->snd_una, th_ack);
+               *newbytes_acked += (tp->snd_fack - tp->snd_una);
+       }
+
        /*
         * In the while-loop below, incoming SACK blocks (sack_blocks[])
         * and SACK holes (snd_holes) are traversed from their tails with
        /*
         * In the while-loop below, incoming SACK blocks (sack_blocks[])
         * and SACK holes (snd_holes) are traversed from their tails with
@@ -390,6 +407,8 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL);
                if (temp != NULL) {
                        tp->snd_fack = sblkp->end;
                temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL);
                if (temp != NULL) {
                        tp->snd_fack = sblkp->end;
+                       *newbytes_acked += (sblkp->end - sblkp->start);
+
                        /* Go to the previous sack block. */
                        sblkp--;
                } else {
                        /* Go to the previous sack block. */
                        sblkp--;
                } else {
@@ -405,12 +424,16 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                               SEQ_LT(tp->snd_fack, sblkp->start))
                                sblkp--;
                        if (sblkp >= sack_blocks && 
                               SEQ_LT(tp->snd_fack, sblkp->start))
                                sblkp--;
                        if (sblkp >= sack_blocks && 
-                           SEQ_LT(tp->snd_fack, sblkp->end))
+                           SEQ_LT(tp->snd_fack, sblkp->end)) {
+                               *newbytes_acked += (sblkp->end - tp->snd_fack);
                                tp->snd_fack = sblkp->end;
                                tp->snd_fack = sblkp->end;
+                       }
                }
                }
-       } else if (SEQ_LT(tp->snd_fack, sblkp->end))
+       } else if (SEQ_LT(tp->snd_fack, sblkp->end)) {
                /* fack is advanced. */
                /* fack is advanced. */
+               *newbytes_acked += (sblkp->end - tp->snd_fack);
                tp->snd_fack = sblkp->end;
                tp->snd_fack = sblkp->end;
+       }
        /* We must have at least one SACK hole in scoreboard */
        cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole */
        /*
        /* We must have at least one SACK hole in scoreboard */
        cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole */
        /*
@@ -439,6 +462,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                        /* Data acks at least the beginning of hole */
                        if (SEQ_GEQ(sblkp->end, cur->end)) {
                                /* Acks entire hole, so delete hole */
                        /* Data acks at least the beginning of hole */
                        if (SEQ_GEQ(sblkp->end, cur->end)) {
                                /* Acks entire hole, so delete hole */
+                               *newbytes_acked += (cur->end - cur->start);
                                temp = cur;
                                cur = TAILQ_PREV(cur, sackhole_head, scblink);
                                tcp_sackhole_remove(tp, temp);
                                temp = cur;
                                cur = TAILQ_PREV(cur, sackhole_head, scblink);
                                tcp_sackhole_remove(tp, temp);
@@ -449,6 +473,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                                continue;
                        } else {
                                /* Move start of hole forward */
                                continue;
                        } else {
                                /* Move start of hole forward */
+                               *newbytes_acked += (sblkp->end - cur->start);
                                cur->start = sblkp->end;
                                cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
                        }
                                cur->start = sblkp->end;
                                cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
                        }
@@ -456,6 +481,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                        /* Data acks at least the end of hole */
                        if (SEQ_GEQ(sblkp->end, cur->end)) {
                                /* Move end of hole backward */
                        /* Data acks at least the end of hole */
                        if (SEQ_GEQ(sblkp->end, cur->end)) {
                                /* Move end of hole backward */
+                               *newbytes_acked += (cur->end - sblkp->start);
                                cur->end = sblkp->start;
                                cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
                        } else {
                                cur->end = sblkp->start;
                                cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
                        } else {
@@ -463,6 +489,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
                                 * ACKs some data in middle of a hole; need to
                                 * split current hole
                                 */
                                 * ACKs some data in middle of a hole; need to
                                 * split current hole
                                 */
+                               *newbytes_acked += (sblkp->end - sblkp->start);
                                temp = tcp_sackhole_insert(tp, sblkp->end,
                                                           cur->end, cur);
                                if (temp != NULL) {
                                temp = tcp_sackhole_insert(tp, sblkp->end,
                                                           cur->end, cur);
                                if (temp != NULL) {
@@ -502,6 +529,8 @@ tcp_free_sackholes(struct tcpcb *tp)
        while ((q = TAILQ_FIRST(&tp->snd_holes)) != NULL)
                tcp_sackhole_remove(tp, q);
        tp->sackhint.sack_bytes_rexmit = 0;
        while ((q = TAILQ_FIRST(&tp->snd_holes)) != NULL)
                tcp_sackhole_remove(tp, q);
        tp->sackhint.sack_bytes_rexmit = 0;
+       tp->sackhint.nexthole = NULL;
+       tp->sack_newdata = 0;
 
 }
 
 
 }
 
@@ -525,7 +554,7 @@ tcp_sack_partialack(tp, th)
        tp->t_timer[TCPT_REXMT] = 0;
        tp->t_rtttime = 0;
        /* send one or 2 segments based on how much new data was acked */
        tp->t_timer[TCPT_REXMT] = 0;
        tp->t_rtttime = 0;
        /* send one or 2 segments based on how much new data was acked */
-       if (((th->th_ack - tp->snd_una) / tp->t_maxseg) > 2)
+       if (((BYTES_ACKED(th, tp)) / tp->t_maxseg) > 2)
                num_segs = 2;
        tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit +
                (tp->snd_nxt - tp->sack_newdata) +
                num_segs = 2;
        tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit +
                (tp->snd_nxt - tp->sack_newdata) +