slow-start-ack-per-xpkt test

// Test of slow start when not application-limited, so that
// the cwnd continues to grow.
// In this variant, the receiver sends one ACK per 4 packets.

// Set up config. To keep things simple, disable the
// mechanism that defers sending in order to send bigger TSO packets.
`../common/defaults.sh
sysctl -q net.ipv4.tcp_tso_win_divisor=100`

    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   +0 bind(3, ..., ...) = 0
   +0 listen(3, 1) = 0

  +.1 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
  +.1 < . 1:1(0) ack 1 win 257
   +0 accept(3, ..., ...) = 4
   +0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0

   +0 write(4, ..., 30000) = 30000
   +0 > P. 1:10001(10000) ack 1
   +0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%

 +.11 < . 1:1(0) ack 4001 win 257
   +0 > P. 10001:18001(8000) ack 1
  +0 %{ print("ack 4001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 

 +.01 < . 1:1(0) ack 8001 win 257
   +0 > P. 18001:26001(8000) ack 1
  +0 %{ print("ack 8001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 

+.005 < . 1:1(0) ack 10001 win 257
   +0 > P. 26001:30001(4000) ack 1
  +0 %{ print("ack 10001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 
  
   +0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%

 

 根据tcp_ack 中的代码可知:ack了新的数据则tcp_may_raise_cwnd ,也就是最后调用tcp_cong_avoid

static void tcp_cong_control(struct sock *sk, u32 ack, u32 acked_sacked,
                 int flag, const struct rate_sample *rs)
{
    const struct inet_connection_sock *icsk = inet_csk(sk);
/*它会尝试调用icsk->icsk_ca_ops中注册的拥塞控制函数,
如果没有注册则采用默认策略:使用传统的窗口减小tcp_cwnd_reduction和增大tcp_cwnd_reduction函数。*/
    if (icsk->icsk_ca_ops->cong_control) {//目前bbr使用
        icsk->icsk_ca_ops->cong_control(sk, rs);
        return;
    }

    if (tcp_in_cwnd_reduction(sk)) {
        /* Reduce cwnd if state mandates */
        tcp_cwnd_reduction(sk, acked_sacked, flag);
    } else if (tcp_may_raise_cwnd(sk, flag)) {
        /* Advance cwnd if state allows */
        tcp_cong_avoid(sk, ack, acked_sacked);
    }
    tcp_update_pacing_rate(sk);
}

 

对于cubic 算法

static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
{
    struct tcp_sock *tp = tcp_sk(sk);
    struct bictcp *ca = inet_csk_ca(sk);

    if (!tcp_is_cwnd_limited(sk))
        return;

    if (tcp_in_slow_start(tp)) {
        if (hystart && after(ack, ca->end_seq))
            bictcp_hystart_reset(sk);
        acked = tcp_slow_start(tp, acked);
        if (!acked)
            return;
    }
    bictcp_update(ca, tp->snd_cwnd, acked);
    tcp_cong_avoid_ai(tp, ca->cnt, acked);
}
/* Slow start is used when congestion window is no greater than the slow start
 * threshold. We base on RFC2581 and also handle stretch ACKs properly.
 * We do not implement RFC3465 Appropriate Byte Counting (ABC) per se but
 * something better;) a packet is only considered (s)acked in its entirety to
 * defend the ACK attacks described in the RFC. Slow start processes a stretch
 * ACK of degree N as if N acks of degree 1 are received back to back except
 * ABC caps N to 2. Slow start exits when cwnd grows over ssthresh and
 * returns the leftover acks to adjust cwnd in congestion avoidance mode.
 */
u32 tcp_slow_start(struct tcp_sock *tp, u32 acked)
{
    u32 cwnd = min(tp->snd_cwnd + acked, tp->snd_ssthresh);

    acked -= cwnd - tp->snd_cwnd;
    tp->snd_cwnd = min(cwnd, tp->snd_cwnd_clamp);

    return acked;
}

 

/* We follow the spirit of RFC2861 to validate cwnd but implement a more
 * flexible approach. The RFC suggests cwnd should not be raised unless
 * it was fully used previously. And that's exactly what we do in
 * congestion avoidance mode. But in slow start we allow cwnd to grow
 * as long as the application has used half the cwnd.
 * Example :
 *    cwnd is 10 (IW10), but application sends 9 frames.
 *    We allow cwnd to reach 18 when all frames are ACKed.
 * This check is safe because it's as aggressive as slow start which already
 * risks 100% overshoot. The advantage is that we discourage application to
 * either send more filler packets or data to artificially blow up the cwnd
 * usage, and allow application-limited process to probe bw more aggressively.
 */
static inline bool tcp_is_cwnd_limited(const struct sock *sk)
{
    const struct tcp_sock *tp = tcp_sk(sk);

    /* If in slow start, ensure cwnd grows to twice what was ACKed. */
    if (tcp_in_slow_start(tp))
        return tp->snd_cwnd < 2 * tp->max_packets_out;

    return tp->is_cwnd_limited;
}

 

初始化:snd_ssthresh = 0x7ffffff   snd_cwnd_clamp = 0xfffffff;

所以可以看到:每次ack几个pkt,snd_cwnd就增长几个

 

// Test of slow start when not application-limited, so that
// the cwnd continues to grow.
// In this variant, the receiver ACKs every other packet,
// approximating standard delayed ACKs.

// Set up config. To keep things simple, disable the
// mechanism that defers sending in order to send bigger TSO packets.
`../common/defaults.sh
sysctl -q net.ipv4.tcp_tso_win_divisor=100`

    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   +0 bind(3, ..., ...) = 0
   +0 listen(3, 1) = 0

  +.1 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
  +.1 < . 1:1(0) ack 1 win 257
   +0 accept(3, ..., ...) = 4
   +0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0

   +0 write(4, ..., 30000) = 30000
   +0 > P. 1:10001(10000) ack 1
   +0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%

+.105 < . 1:1(0) ack 2001 win 257
   +0 > P. 10001:14001(4000) ack 1
    +0 %{ print("ack 2001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 

+.005 < . 1:1(0) ack 4001 win 257
   +0 > P. 14001:18001(4000) ack 1
    +0 %{ print("ack 4001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 

+.005 < . 1:1(0) ack 6001 win 257
   +0 > P. 18001:22001(4000) ack 1
    +0 %{ print("ack 6001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 

+.005 < . 1:1(0) ack 8001 win 257
   +0 > P. 22001:26001(4000) ack 1
    +0 %{ print("ack 8001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 

+.005 < . 1:1(0) ack 10001 win 257
   +0 > P. 26001:30001(4000) ack 1
    +0 %{ print("ack 10001:", "tcpi_snd_cwnd:", tcpi_snd_cwnd, "tcpi_snd_ssthresh", tcpi_snd_ssthresh) }% 
   +0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%

 

但是如果是如果send pkt只有5呢?

// Set up config.
`../common/defaults.sh`

    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   +0 bind(3, ..., ...) = 0
   +0 listen(3, 1) = 0

   +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
   +0 < . 1:1(0) ack 1 win 257
   +0 accept(3, ..., ...) = 4

// Only send 5 packets.
   +0 write(4, ..., 5000) = 5000
   +0 > P. 1:5001(5000) ack 1
   +0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%

   +0 < . 1:1(0) ack 2001 win 257
   +0 %{ assert tcpi_snd_cwnd == 10, 'cwnd=%d' % tcpi_snd_cwnd }%

   +0 < . 1:1(0) ack 4001 win 257
   +0 %{ assert tcpi_snd_cwnd == 10, 'cwnd=%d' % tcpi_snd_cwnd }%

   +0 < . 1:1(0) ack 5001 win 257
   +0 %{ assert tcpi_snd_cwnd == 10, 'cwnd=%d' % tcpi_snd_cwnd }%

 

 也就是cwnd不会增长,原因就是 tcp_is_cwnd_limited  的判断方法!!

 /* If in slow start, ensure cwnd grows to twice what was ACKed. */
    if (tcp_in_slow_start(tp))
        return tp->snd_cwnd < 2 * tp->max_packets_out;

 

 也就是如果tp->snd_cwnd >= 2 * tp->max_packets_out;   此时认为是 app_limitedm,则不会进行拥塞调整。

所以下面例子;如果send 7 pkt,当ack了4pkt后, cwnd增长到14, 即使后面ack了5001  6001 7001,由于此时cwnd >=    pkt_out*2  ;不会调整cwnd

// Set up config.
`../common/defaults.sh`

    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   +0 bind(3, ..., ...) = 0
   +0 listen(3, 1) = 0

   +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
   +0 < . 1:1(0) ack 1 win 257
   +0 accept(3, ..., ...) = 4

// Only send 5 packets.
   +0 write(4, ..., 7000) = 7000
   +0 > P. 1:7001(7000) ack 1
   +0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
   +0 %{ print("ack 0:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 2001 win 257
   +0 %{ print("ack 2:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 3001 win 257
   +0 %{ print("ack 3:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 4001 win 257
   +0 %{ print("ack 4:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 5001 win 257
   +0 %{ print("ack 5:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

      +0 < . 1:1(0) ack 7001 win 257
   +0 %{ print("ack 7:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 
  // +0 `sleep 1`

/*
ack 0: tcpi_snd_cwnd: 10
ack 2: tcpi_snd_cwnd: 12
ack 3: tcpi_snd_cwnd: 13
ack 4: tcpi_snd_cwnd: 14
ack 5: tcpi_snd_cwnd: 14
ack 7: tcpi_snd_cwnd: 14

*/

 

再看一个样例:

 

   +0 write(4, ..., 8000) = 8000
   +0 > P. 1:8001(8000) ack 1
   +0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
   +0 %{ print("ack 0:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 2001 win 257
   +0 %{ print("ack 2:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 3001 win 257
   +0 %{ print("ack 3:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 4001 win 257
   +0 %{ print("ack 4:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 5001 win 257
   +0 %{ print("ack 5:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

    +0 < . 1:1(0) ack 6001 win 257  // 屏蔽和不屏蔽掉此语句对比
   +0 %{ print("ack 6:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 7001 win 257
   +0 %{ print("ack 7:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 

   +0 < . 1:1(0) ack 8001 win 257
   +0 %{ print("ack 8:", "tcpi_snd_cwnd:", tcpi_snd_cwnd) }% 
  // +0 `sleep 1`

 

如果屏蔽掉+0 < . 1:1(0) ack 6001 win 257 

 

可以看出此时 ack 7 时 从cwnd达到最大10+7 >=2*8

 

如果执行+0 < . 1:1(0) ack 6001 win 257 

 可以看出此时 ack 6  时 从cwnd达到最大10+6   >= 2*8

 

posted @ 2024-12-18 02:02  codestacklinuxer  阅读(21)  评论(0)    收藏  举报