diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b794f89ac1f2..836d74dd0187 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2682,6 +2682,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk, const bool set_ssthresh) | |||
2682 | struct tcp_sock *tp = tcp_sk(sk); | 2682 | struct tcp_sock *tp = tcp_sk(sk); |
2683 | 2683 | ||
2684 | tp->high_seq = tp->snd_nxt; | 2684 | tp->high_seq = tp->snd_nxt; |
2685 | tp->tlp_high_seq = 0; | ||
2685 | tp->snd_cwnd_cnt = 0; | 2686 | tp->snd_cwnd_cnt = 0; |
2686 | tp->prior_cwnd = tp->snd_cwnd; | 2687 | tp->prior_cwnd = tp->snd_cwnd; |
2687 | tp->prr_delivered = 0; | 2688 | tp->prr_delivered = 0; |
@@ -3569,6 +3570,38 @@ static void tcp_send_challenge_ack(struct sock *sk) | |||
3569 | } | 3570 | } |
3570 | } | 3571 | } |
3571 | 3572 | ||
3573 | /* This routine deals with acks during a TLP episode. | ||
3574 | * Ref: loss detection algorithm in draft-dukkipati-tcpm-tcp-loss-probe. | ||
3575 | */ | ||
3576 | static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) | ||
3577 | { | ||
3578 | struct tcp_sock *tp = tcp_sk(sk); | ||
3579 | bool is_tlp_dupack = (ack == tp->tlp_high_seq) && | ||
3580 | !(flag & (FLAG_SND_UNA_ADVANCED | | ||
3581 | FLAG_NOT_DUP | FLAG_DATA_SACKED)); | ||
3582 | |||
3583 | /* Mark the end of TLP episode on receiving TLP dupack or when | ||
3584 | * ack is after tlp_high_seq. | ||
3585 | */ | ||
3586 | if (is_tlp_dupack) { | ||
3587 | tp->tlp_high_seq = 0; | ||
3588 | return; | ||
3589 | } | ||
3590 | |||
3591 | if (after(ack, tp->tlp_high_seq)) { | ||
3592 | tp->tlp_high_seq = 0; | ||
3593 | /* Don't reduce cwnd if DSACK arrives for TLP retrans. */ | ||
3594 | if (!(flag & FLAG_DSACKING_ACK)) { | ||
3595 | tcp_init_cwnd_reduction(sk, true); | ||
3596 | tcp_set_ca_state(sk, TCP_CA_CWR); | ||
3597 | tcp_end_cwnd_reduction(sk); | ||
3598 | tcp_set_ca_state(sk, TCP_CA_Open); | ||
3599 | NET_INC_STATS_BH(sock_net(sk), | ||
3600 | LINUX_MIB_TCPLOSSPROBERECOVERY); | ||
3601 | } | ||
3602 | } | ||
3603 | } | ||
3604 | |||
3572 | /* This routine deals with incoming acks, but not outgoing ones. */ | 3605 | /* This routine deals with incoming acks, but not outgoing ones. */ |
3573 | static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | 3606 | static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) |
3574 | { | 3607 | { |
@@ -3676,6 +3709,9 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | |||
3676 | tcp_cong_avoid(sk, ack, prior_in_flight); | 3709 | tcp_cong_avoid(sk, ack, prior_in_flight); |
3677 | } | 3710 | } |
3678 | 3711 | ||
3712 | if (tp->tlp_high_seq) | ||
3713 | tcp_process_tlp_ack(sk, ack, flag); | ||
3714 | |||
3679 | if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) { | 3715 | if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) { |
3680 | struct dst_entry *dst = __sk_dst_get(sk); | 3716 | struct dst_entry *dst = __sk_dst_get(sk); |
3681 | if (dst) | 3717 | if (dst) |
@@ -3697,6 +3733,9 @@ no_queue: | |||
3697 | */ | 3733 | */ |
3698 | if (tcp_send_head(sk)) | 3734 | if (tcp_send_head(sk)) |
3699 | tcp_ack_probe(sk); | 3735 | tcp_ack_probe(sk); |
3736 | |||
3737 | if (tp->tlp_high_seq) | ||
3738 | tcp_process_tlp_ack(sk, ack, flag); | ||
3700 | return 1; | 3739 | return 1; |
3701 | 3740 | ||
3702 | invalid_ack: | 3741 | invalid_ack: |