]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/tcp_cubic.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / bsd / netinet / tcp_cubic.c
index 2eb86f1a91e8645e4f21ff5ac4f5fad74b26bfa1..c9ce59c04dbccb8418bc0464733ac00cb8f956cd 100644 (file)
@@ -89,20 +89,14 @@ const float tcp_cubic_backoff = 0.2; /* multiplicative decrease factor */
 const float tcp_cubic_coeff = 0.4;
 const float tcp_cubic_fast_convergence_factor = 0.875;
 
-static int tcp_cubic_tcp_friendliness = 0;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, cubic_tcp_friendliness,
-       CTLFLAG_RW | CTLFLAG_LOCKED, &tcp_cubic_tcp_friendliness, 0,
-       "Enable TCP friendliness");
+SYSCTL_SKMEM_TCP_INT(OID_AUTO, cubic_tcp_friendliness, CTLFLAG_RW | CTLFLAG_LOCKED,
+       static int, tcp_cubic_tcp_friendliness, 0, "Enable TCP friendliness");
 
-static int tcp_cubic_fast_convergence = 0;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, cubic_fast_convergence,
-       CTLFLAG_RW | CTLFLAG_LOCKED, &tcp_cubic_fast_convergence, 0,
-       "Enable fast convergence");
+SYSCTL_SKMEM_TCP_INT(OID_AUTO, cubic_fast_convergence, CTLFLAG_RW | CTLFLAG_LOCKED,
+       static int, tcp_cubic_fast_convergence, 0, "Enable fast convergence");
 
-static int tcp_cubic_use_minrtt = 0;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, cubic_use_minrtt,
-       CTLFLAG_RW | CTLFLAG_LOCKED, &tcp_cubic_use_minrtt, 0,
-       "use a min of 5 sec rtt");
+SYSCTL_SKMEM_TCP_INT(OID_AUTO, cubic_use_minrtt, CTLFLAG_RW | CTLFLAG_LOCKED,
+       static int, tcp_cubic_use_minrtt, 0, "use a min of 5 sec rtt");
 
 static int tcp_cubic_init(struct tcpcb *tp)
 {
@@ -130,6 +124,11 @@ static void tcp_cubic_cwnd_init_or_reset(struct tcpcb *tp)
 
        tcp_cubic_clear_state(tp);
        tcp_cc_cwnd_init_or_reset(tp);
+       tp->t_pipeack = 0;
+       tcp_clear_pipeack_state(tp);
+
+       /* Start counting bytes for RFC 3465 again */
+       tp->t_bytes_acked = 0;
 
        /*
         * slow start threshold could get initialized to a lower value
@@ -144,9 +143,6 @@ static void tcp_cubic_cwnd_init_or_reset(struct tcpcb *tp)
 
        /* Initialize cubic last max to be same as ssthresh */
        tp->t_ccstate->cub_last_max = tp->snd_ssthresh;
-
-       /* If stretch ack was auto-disabled, re-evaluate it */
-       tcp_cc_after_idle_stretchack(tp);
 }
 
 /*
@@ -212,7 +208,7 @@ tcp_cubic_update(struct tcpcb *tp, u_int32_t rtt)
        var = (elapsed_time  - tp->t_ccstate->cub_epoch_period) / TCP_RETRANSHZ;
        var = var * var * var * (tcp_cubic_coeff * tp->t_maxseg);
 
-       tp->t_ccstate->cub_target_win = tp->t_ccstate->cub_origin_point + var;
+       tp->t_ccstate->cub_target_win = (u_int32_t)(tp->t_ccstate->cub_origin_point + var);
        return (tp->t_ccstate->cub_target_win);
 }
 
@@ -273,6 +269,10 @@ tcp_cubic_congestion_avd(struct tcpcb *tp, struct tcphdr *th)
 {
        u_int32_t cubic_target_win, tcp_win, rtt;
 
+       /* Do not increase congestion window in non-validated phase */
+       if (tcp_cc_is_cwnd_nonvalidated(tp) != 0)
+               return;
+
        tp->t_bytes_acked += BYTES_ACKED(th, tp);
 
        rtt = get_base_rtt(tp);
@@ -320,6 +320,10 @@ tcp_cubic_congestion_avd(struct tcpcb *tp, struct tcphdr *th)
 static void
 tcp_cubic_ack_rcvd(struct tcpcb *tp, struct tcphdr *th)
 {
+       /* Do not increase the congestion window in non-validated phase */
+       if (tcp_cc_is_cwnd_nonvalidated(tp) != 0)
+               return;
+
        if (tp->snd_cwnd >= tp->snd_ssthresh) {
                /* Congestion avoidance phase */
                tcp_cubic_congestion_avd(tp, th);
@@ -329,6 +333,7 @@ tcp_cubic_ack_rcvd(struct tcpcb *tp, struct tcphdr *th)
                 * by RFC 3465 section 2.3
                 */
                uint32_t acked, abc_lim, incr;
+
                acked = BYTES_ACKED(th, tp);
                abc_lim = (tcp_do_rfc3465_lim2 && 
                        tp->snd_nxt == tp->snd_max) ?
@@ -344,7 +349,7 @@ tcp_cubic_ack_rcvd(struct tcpcb *tp, struct tcphdr *th)
 static void
 tcp_cubic_pre_fr(struct tcpcb *tp)
 {
-       uint32_t win, avg;
+       u_int32_t win, avg;
        int32_t dev;
        tp->t_ccstate->cub_epoch_start = 0;
        tp->t_ccstate->cub_tcp_win = 0;
@@ -352,6 +357,12 @@ tcp_cubic_pre_fr(struct tcpcb *tp)
        tp->t_ccstate->cub_tcp_bytes_acked = 0;
 
        win = min(tp->snd_cwnd, tp->snd_wnd);
+       if (tp->t_flagsext & TF_CWND_NONVALIDATED) {
+               tp->t_lossflightsize = tp->snd_max - tp->snd_una;
+               win = (max(tp->t_pipeack, tp->t_lossflightsize)) >> 1;
+       } else {
+               tp->t_lossflightsize = 0;
+       }
        /*
         * Note the congestion window at which packet loss occurred as
         * cub_last_max.
@@ -365,8 +376,8 @@ tcp_cubic_pre_fr(struct tcpcb *tp)
         */
        if (win < tp->t_ccstate->cub_last_max &&
                tcp_cubic_fast_convergence == 1)
-               tp->t_ccstate->cub_last_max = win * 
-                       tcp_cubic_fast_convergence_factor;
+               tp->t_ccstate->cub_last_max = (u_int32_t)(win *
+                       tcp_cubic_fast_convergence_factor);
        else
                tp->t_ccstate->cub_last_max = win;
 
@@ -412,7 +423,7 @@ tcp_cubic_pre_fr(struct tcpcb *tp)
        }
 
        /* Backoff congestion window by tcp_cubic_backoff factor */
-       win = win - (win * tcp_cubic_backoff);
+       win = (u_int32_t)(win - (win * tcp_cubic_backoff));
        win = (win / tp->t_maxseg);
        if (win < 2)
                win = 2;
@@ -427,6 +438,27 @@ tcp_cubic_post_fr(struct tcpcb *tp, struct tcphdr *th)
 
        if (SEQ_LEQ(th->th_ack, tp->snd_max))
                flight_size = tp->snd_max - th->th_ack;
+
+       if (SACK_ENABLED(tp) && tp->t_lossflightsize > 0) {
+               u_int32_t total_rxt_size = 0, ncwnd;
+               /*
+                * When SACK is enabled, the number of retransmitted bytes
+                * can be counted more accurately.
+                */
+               total_rxt_size = tcp_rxtseg_total_size(tp);
+               ncwnd = max(tp->t_pipeack, tp->t_lossflightsize);
+               if (total_rxt_size <= ncwnd) {
+                       ncwnd = ncwnd - total_rxt_size;
+               }
+
+               /*
+                * To avoid sending a large burst at the end of recovery
+                * set a max limit on ncwnd
+                */
+               ncwnd = min(ncwnd, (tp->t_maxseg << 6));
+               ncwnd = ncwnd >> 1;
+               flight_size = max(ncwnd, flight_size);
+       }
        /*
         * Complete ack. The current window was inflated for fast recovery.
         * It has to be deflated post recovery.
@@ -450,6 +482,16 @@ static void
 tcp_cubic_after_timeout(struct tcpcb *tp)
 {
        VERIFY(tp->t_ccstate != NULL);
+
+       /*
+        * Avoid adjusting congestion window due to SYN retransmissions.
+        * If more than one byte (SYN) is outstanding then it is still
+        * needed to adjust the window.
+        */
+       if (tp->t_state < TCPS_ESTABLISHED &&
+           ((int)(tp->snd_max - tp->snd_una) <= 1))
+               return;
+
        if (!IN_FASTRECOVERY(tp)) {
                tcp_cubic_clear_state(tp);
                tcp_cubic_pre_fr(tp);
@@ -479,8 +521,6 @@ tcp_cubic_switch_cc(struct tcpcb *tp, uint16_t old_cc_index)
 {
 #pragma unused(old_cc_index)
        tcp_cubic_cwnd_init_or_reset(tp);
-       /* Start counting bytes for RFC 3465 again */
-       tp->t_bytes_acked = 0;
 
        OSIncrementAtomic((volatile SInt32 *)&tcp_cc_cubic.num_sockets);
 }