|
|
|
@ -842,18 +842,6 @@ __u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst)
|
|
|
|
|
return min_t(__u32, cwnd, tp->snd_cwnd_clamp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Packet counting of FACK is based on in-order assumptions, therefore TCP
|
|
|
|
|
* disables it when reordering is detected
|
|
|
|
|
*/
|
|
|
|
|
void tcp_disable_fack(struct tcp_sock *tp)
|
|
|
|
|
{
|
|
|
|
|
/* RFC3517 uses different metric in lost marker => reset on change */
|
|
|
|
|
if (tcp_is_fack(tp))
|
|
|
|
|
tp->lost_skb_hint = NULL;
|
|
|
|
|
tp->rx_opt.sack_ok &= ~TCP_FACK_ENABLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Take a notice that peer is sending D-SACKs */
|
|
|
|
|
static void tcp_dsack_seen(struct tcp_sock *tp)
|
|
|
|
|
{
|
|
|
|
@ -861,42 +849,39 @@ static void tcp_dsack_seen(struct tcp_sock *tp)
|
|
|
|
|
tp->rack.dsack_seen = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void tcp_update_reordering(struct sock *sk, const int metric,
|
|
|
|
|
const int ts)
|
|
|
|
|
/* It's reordering when higher sequence was delivered (i.e. sacked) before
|
|
|
|
|
* some lower never-retransmitted sequence ("low_seq"). The maximum reordering
|
|
|
|
|
* distance is approximated in full-mss packet distance ("reordering").
|
|
|
|
|
*/
|
|
|
|
|
static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq,
|
|
|
|
|
const int ts)
|
|
|
|
|
{
|
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
int mib_idx;
|
|
|
|
|
const u32 mss = tp->mss_cache;
|
|
|
|
|
u32 fack, metric;
|
|
|
|
|
|
|
|
|
|
if (WARN_ON_ONCE(metric < 0))
|
|
|
|
|
fack = tcp_highest_sack_seq(tp);
|
|
|
|
|
if (!before(low_seq, fack))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (metric > tp->reordering) {
|
|
|
|
|
tp->reordering = min(sock_net(sk)->ipv4.sysctl_tcp_max_reordering, metric);
|
|
|
|
|
|
|
|
|
|
metric = fack - low_seq;
|
|
|
|
|
if ((metric > tp->reordering * mss) && mss) {
|
|
|
|
|
#if FASTRETRANS_DEBUG > 1
|
|
|
|
|
pr_debug("Disorder%d %d %u f%u s%u rr%d\n",
|
|
|
|
|
tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state,
|
|
|
|
|
tp->reordering,
|
|
|
|
|
tp->fackets_out,
|
|
|
|
|
0,
|
|
|
|
|
tp->sacked_out,
|
|
|
|
|
tp->undo_marker ? tp->undo_retrans : 0);
|
|
|
|
|
#endif
|
|
|
|
|
tcp_disable_fack(tp);
|
|
|
|
|
tp->reordering = min_t(u32, (metric + mss - 1) / mss,
|
|
|
|
|
sock_net(sk)->ipv4.sysctl_tcp_max_reordering);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tp->rack.reord = 1;
|
|
|
|
|
|
|
|
|
|
/* This exciting event is worth to be remembered. 8) */
|
|
|
|
|
if (ts)
|
|
|
|
|
mib_idx = LINUX_MIB_TCPTSREORDER;
|
|
|
|
|
else if (tcp_is_reno(tp))
|
|
|
|
|
mib_idx = LINUX_MIB_TCPRENOREORDER;
|
|
|
|
|
else if (tcp_is_fack(tp))
|
|
|
|
|
mib_idx = LINUX_MIB_TCPFACKREORDER;
|
|
|
|
|
else
|
|
|
|
|
mib_idx = LINUX_MIB_TCPSACKREORDER;
|
|
|
|
|
|
|
|
|
|
NET_INC_STATS(sock_net(sk), mib_idx);
|
|
|
|
|
NET_INC_STATS(sock_net(sk),
|
|
|
|
|
ts ? LINUX_MIB_TCPTSREORDER : LINUX_MIB_TCPSACKREORDER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This must be called before lost_out is incremented */
|
|
|
|
@ -970,7 +955,6 @@ void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb)
|
|
|
|
|
* 3. Loss detection event of two flavors:
|
|
|
|
|
* A. Scoreboard estimator decided the packet is lost.
|
|
|
|
|
* A'. Reno "three dupacks" marks head of queue lost.
|
|
|
|
|
* A''. Its FACK modification, head until snd.fack is lost.
|
|
|
|
|
* B. SACK arrives sacking SND.NXT at the moment, when the
|
|
|
|
|
* segment was retransmitted.
|
|
|
|
|
* 4. D-SACK added new rule: D-SACK changes any tag to S.
|
|
|
|
@ -1113,8 +1097,7 @@ static bool tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct tcp_sacktag_state {
|
|
|
|
|
int reord;
|
|
|
|
|
int fack_count;
|
|
|
|
|
u32 reord;
|
|
|
|
|
/* Timestamps for earliest and latest never-retransmitted segment
|
|
|
|
|
* that was SACKed. RTO needs the earliest RTT to stay conservative,
|
|
|
|
|
* but congestion control should still get an accurate delay signal.
|
|
|
|
@ -1190,15 +1173,15 @@ static u8 tcp_sacktag_one(struct sock *sk,
|
|
|
|
|
u64 xmit_time)
|
|
|
|
|
{
|
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
int fack_count = state->fack_count;
|
|
|
|
|
|
|
|
|
|
/* Account D-SACK for retransmitted packet. */
|
|
|
|
|
if (dup_sack && (sacked & TCPCB_RETRANS)) {
|
|
|
|
|
if (tp->undo_marker && tp->undo_retrans > 0 &&
|
|
|
|
|
after(end_seq, tp->undo_marker))
|
|
|
|
|
tp->undo_retrans--;
|
|
|
|
|
if (sacked & TCPCB_SACKED_ACKED)
|
|
|
|
|
state->reord = min(fack_count, state->reord);
|
|
|
|
|
if ((sacked & TCPCB_SACKED_ACKED) &&
|
|
|
|
|
before(start_seq, state->reord))
|
|
|
|
|
state->reord = start_seq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Nothing to do; acked frame is about to be dropped (was ACKed). */
|
|
|
|
@ -1224,9 +1207,10 @@ static u8 tcp_sacktag_one(struct sock *sk,
|
|
|
|
|
* which was in hole. It is reordering.
|
|
|
|
|
*/
|
|
|
|
|
if (before(start_seq,
|
|
|
|
|
tcp_highest_sack_seq(tp)))
|
|
|
|
|
state->reord = min(fack_count,
|
|
|
|
|
state->reord);
|
|
|
|
|
tcp_highest_sack_seq(tp)) &&
|
|
|
|
|
before(start_seq, state->reord))
|
|
|
|
|
state->reord = start_seq;
|
|
|
|
|
|
|
|
|
|
if (!after(end_seq, tp->high_seq))
|
|
|
|
|
state->flag |= FLAG_ORIG_SACK_ACKED;
|
|
|
|
|
if (state->first_sackt == 0)
|
|
|
|
@ -1245,15 +1229,10 @@ static u8 tcp_sacktag_one(struct sock *sk,
|
|
|
|
|
tp->sacked_out += pcount;
|
|
|
|
|
tp->delivered += pcount; /* Out-of-order packets delivered */
|
|
|
|
|
|
|
|
|
|
fack_count += pcount;
|
|
|
|
|
|
|
|
|
|
/* Lost marker hint past SACKed? Tweak RFC3517 cnt */
|
|
|
|
|
if (!tcp_is_fack(tp) && tp->lost_skb_hint &&
|
|
|
|
|
if (tp->lost_skb_hint &&
|
|
|
|
|
before(start_seq, TCP_SKB_CB(tp->lost_skb_hint)->seq))
|
|
|
|
|
tp->lost_cnt_hint += pcount;
|
|
|
|
|
|
|
|
|
|
if (fack_count > tp->fackets_out)
|
|
|
|
|
tp->fackets_out = fack_count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* D-SACK. We can detect redundant retransmission in S|R and plain R
|
|
|
|
@ -1500,7 +1479,6 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
state->fack_count += pcount;
|
|
|
|
|
return prev;
|
|
|
|
|
|
|
|
|
|
noop:
|
|
|
|
@ -1579,8 +1557,6 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
|
|
|
|
|
tcp_highest_sack_seq(tp)))
|
|
|
|
|
tcp_advance_highest_sack(sk, skb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state->fack_count += tcp_skb_pcount(skb);
|
|
|
|
|
}
|
|
|
|
|
return skb;
|
|
|
|
|
}
|
|
|
|
@ -1591,7 +1567,6 @@ static struct sk_buff *tcp_sacktag_bsearch(struct sock *sk,
|
|
|
|
|
{
|
|
|
|
|
struct rb_node *parent, **p = &sk->tcp_rtx_queue.rb_node;
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
int unack_bytes;
|
|
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
|
parent = *p;
|
|
|
|
@ -1604,12 +1579,6 @@ static struct sk_buff *tcp_sacktag_bsearch(struct sock *sk,
|
|
|
|
|
p = &parent->rb_right;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state->fack_count = 0;
|
|
|
|
|
unack_bytes = TCP_SKB_CB(skb)->seq - tcp_sk(sk)->snd_una;
|
|
|
|
|
if (state->mss_now && unack_bytes > 0)
|
|
|
|
|
state->fack_count = unack_bytes / state->mss_now;
|
|
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
@ -1667,13 +1636,10 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
|
|
|
|
|
int first_sack_index;
|
|
|
|
|
|
|
|
|
|
state->flag = 0;
|
|
|
|
|
state->reord = tp->packets_out;
|
|
|
|
|
state->reord = tp->snd_nxt;
|
|
|
|
|
|
|
|
|
|
if (!tp->sacked_out) {
|
|
|
|
|
if (WARN_ON(tp->fackets_out))
|
|
|
|
|
tp->fackets_out = 0;
|
|
|
|
|
if (!tp->sacked_out)
|
|
|
|
|
tcp_highest_sack_reset(sk);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
found_dup_sack = tcp_check_dsack(sk, ack_skb, sp_wire,
|
|
|
|
|
num_sacks, prior_snd_una);
|
|
|
|
@ -1745,7 +1711,6 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state->mss_now = tcp_current_mss(sk);
|
|
|
|
|
state->fack_count = 0;
|
|
|
|
|
skb = NULL;
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
|
@ -1803,7 +1768,6 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
|
|
|
|
|
skb = tcp_highest_sack(sk);
|
|
|
|
|
if (!skb)
|
|
|
|
|
break;
|
|
|
|
|
state->fack_count = tp->fackets_out;
|
|
|
|
|
cache++;
|
|
|
|
|
goto walk;
|
|
|
|
|
}
|
|
|
|
@ -1818,7 +1782,6 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
|
|
|
|
|
skb = tcp_highest_sack(sk);
|
|
|
|
|
if (!skb)
|
|
|
|
|
break;
|
|
|
|
|
state->fack_count = tp->fackets_out;
|
|
|
|
|
}
|
|
|
|
|
skb = tcp_sacktag_skip(skb, sk, state, start_seq);
|
|
|
|
|
|
|
|
|
@ -1838,9 +1801,8 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
|
|
|
|
|
for (j = 0; j < used_sacks; j++)
|
|
|
|
|
tp->recv_sack_cache[i++] = sp[j];
|
|
|
|
|
|
|
|
|
|
if ((state->reord < tp->fackets_out) &&
|
|
|
|
|
((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker))
|
|
|
|
|
tcp_update_reordering(sk, tp->fackets_out - state->reord, 0);
|
|
|
|
|
if (inet_csk(sk)->icsk_ca_state != TCP_CA_Loss || tp->undo_marker)
|
|
|
|
|
tcp_check_sack_reordering(sk, state->reord, 0);
|
|
|
|
|
|
|
|
|
|
tcp_verify_left_out(tp);
|
|
|
|
|
out:
|
|
|
|
@ -1878,8 +1840,13 @@ static bool tcp_limit_reno_sacked(struct tcp_sock *tp)
|
|
|
|
|
static void tcp_check_reno_reordering(struct sock *sk, const int addend)
|
|
|
|
|
{
|
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
if (tcp_limit_reno_sacked(tp))
|
|
|
|
|
tcp_update_reordering(sk, tp->packets_out + addend, 0);
|
|
|
|
|
|
|
|
|
|
if (!tcp_limit_reno_sacked(tp))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
tp->reordering = min_t(u32, tp->packets_out + addend,
|
|
|
|
|
sock_net(sk)->ipv4.sysctl_tcp_max_reordering);
|
|
|
|
|
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Emulate SACKs for SACKless connection: account for a new dupack. */
|
|
|
|
@ -1925,7 +1892,6 @@ void tcp_clear_retrans(struct tcp_sock *tp)
|
|
|
|
|
tp->lost_out = 0;
|
|
|
|
|
tp->undo_marker = 0;
|
|
|
|
|
tp->undo_retrans = -1;
|
|
|
|
|
tp->fackets_out = 0;
|
|
|
|
|
tp->sacked_out = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1975,7 +1941,6 @@ void tcp_enter_loss(struct sock *sk)
|
|
|
|
|
if (is_reneg) {
|
|
|
|
|
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSACKRENEGING);
|
|
|
|
|
tp->sacked_out = 0;
|
|
|
|
|
tp->fackets_out = 0;
|
|
|
|
|
}
|
|
|
|
|
tcp_clear_all_retrans_hints(tp);
|
|
|
|
|
|
|
|
|
@ -2042,19 +2007,10 @@ static bool tcp_check_sack_reneging(struct sock *sk, int flag)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int tcp_fackets_out(const struct tcp_sock *tp)
|
|
|
|
|
{
|
|
|
|
|
return tcp_is_reno(tp) ? tp->sacked_out + 1 : tp->fackets_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Heurestics to calculate number of duplicate ACKs. There's no dupACKs
|
|
|
|
|
* counter when SACK is enabled (without SACK, sacked_out is used for
|
|
|
|
|
* that purpose).
|
|
|
|
|
*
|
|
|
|
|
* Instead, with FACK TCP uses fackets_out that includes both SACKed
|
|
|
|
|
* segments up to the highest received SACK block so far and holes in
|
|
|
|
|
* between them.
|
|
|
|
|
*
|
|
|
|
|
* With reordering, holes may still be in flight, so RFC3517 recovery
|
|
|
|
|
* uses pure sacked_out (total number of SACKed segments) even though
|
|
|
|
|
* it violates the RFC that uses duplicate ACKs, often these are equal
|
|
|
|
@ -2064,10 +2020,10 @@ static inline int tcp_fackets_out(const struct tcp_sock *tp)
|
|
|
|
|
*/
|
|
|
|
|
static inline int tcp_dupack_heuristics(const struct tcp_sock *tp)
|
|
|
|
|
{
|
|
|
|
|
return tcp_is_fack(tp) ? tp->fackets_out : tp->sacked_out + 1;
|
|
|
|
|
return tp->sacked_out + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Linux NewReno/SACK/FACK/ECN state machine.
|
|
|
|
|
/* Linux NewReno/SACK/ECN state machine.
|
|
|
|
|
* --------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* "Open" Normal state, no dubious events, fast path.
|
|
|
|
@ -2132,16 +2088,6 @@ static inline int tcp_dupack_heuristics(const struct tcp_sock *tp)
|
|
|
|
|
* dynamically measured and adjusted. This is implemented in
|
|
|
|
|
* tcp_rack_mark_lost.
|
|
|
|
|
*
|
|
|
|
|
* FACK (Disabled by default. Subsumbed by RACK):
|
|
|
|
|
* It is the simplest heuristics. As soon as we decided
|
|
|
|
|
* that something is lost, we decide that _all_ not SACKed
|
|
|
|
|
* packets until the most forward SACK are lost. I.e.
|
|
|
|
|
* lost_out = fackets_out - sacked_out and left_out = fackets_out.
|
|
|
|
|
* It is absolutely correct estimate, if network does not reorder
|
|
|
|
|
* packets. And it loses any connection to reality when reordering
|
|
|
|
|
* takes place. We use FACK by default until reordering
|
|
|
|
|
* is suspected on the path to this destination.
|
|
|
|
|
*
|
|
|
|
|
* If the receiver does not support SACK:
|
|
|
|
|
*
|
|
|
|
|
* NewReno (RFC6582): in Recovery we assume that one segment
|
|
|
|
@ -2190,7 +2136,7 @@ static bool tcp_time_to_recover(struct sock *sk, int flag)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Detect loss in event "A" above by marking head of queue up as lost.
|
|
|
|
|
* For FACK or non-SACK(Reno) senders, the first "packets" number of segments
|
|
|
|
|
* For non-SACK(Reno) senders, the first "packets" number of segments
|
|
|
|
|
* are considered lost. For RFC3517 SACK, a segment is considered lost if it
|
|
|
|
|
* has at least tp->reordering SACKed seqments above it; "packets" refers to
|
|
|
|
|
* the maximum SACKed segments to pass before reaching this limit.
|
|
|
|
@ -2226,12 +2172,12 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
oldcnt = cnt;
|
|
|
|
|
if (tcp_is_fack(tp) || tcp_is_reno(tp) ||
|
|
|
|
|
if (tcp_is_reno(tp) ||
|
|
|
|
|
(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
|
|
|
|
|
cnt += tcp_skb_pcount(skb);
|
|
|
|
|
|
|
|
|
|
if (cnt > packets) {
|
|
|
|
|
if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) ||
|
|
|
|
|
if (tcp_is_sack(tp) ||
|
|
|
|
|
(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) ||
|
|
|
|
|
(oldcnt >= packets))
|
|
|
|
|
break;
|
|
|
|
@ -2262,11 +2208,6 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
|
|
|
|
|
|
|
|
|
|
if (tcp_is_reno(tp)) {
|
|
|
|
|
tcp_mark_head_lost(sk, 1, 1);
|
|
|
|
|
} else if (tcp_is_fack(tp)) {
|
|
|
|
|
int lost = tp->fackets_out - tp->reordering;
|
|
|
|
|
if (lost <= 0)
|
|
|
|
|
lost = 1;
|
|
|
|
|
tcp_mark_head_lost(sk, lost, 0);
|
|
|
|
|
} else {
|
|
|
|
|
int sacked_upto = tp->sacked_out - tp->reordering;
|
|
|
|
|
if (sacked_upto >= 0)
|
|
|
|
@ -2736,15 +2677,15 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Undo during fast recovery after partial ACK. */
|
|
|
|
|
static bool tcp_try_undo_partial(struct sock *sk, const int acked)
|
|
|
|
|
static bool tcp_try_undo_partial(struct sock *sk, u32 prior_snd_una)
|
|
|
|
|
{
|
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
|
|
|
|
|
if (tp->undo_marker && tcp_packet_delayed(tp)) {
|
|
|
|
|
/* Plain luck! Hole if filled with delayed
|
|
|
|
|
* packet, rather than with a retransmit.
|
|
|
|
|
* packet, rather than with a retransmit. Check reordering.
|
|
|
|
|
*/
|
|
|
|
|
tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1);
|
|
|
|
|
tcp_check_sack_reordering(sk, prior_snd_una, 1);
|
|
|
|
|
|
|
|
|
|
/* We are getting evidence that the reordering degree is higher
|
|
|
|
|
* than we realized. If there are no retransmits out then we
|
|
|
|
@ -2780,6 +2721,14 @@ static void tcp_rack_identify_loss(struct sock *sk, int *ack_flag)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool tcp_force_fast_retransmit(struct sock *sk)
|
|
|
|
|
{
|
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
|
|
|
|
|
return after(tcp_highest_sack_seq(tp),
|
|
|
|
|
tp->snd_una + tp->reordering * tp->mss_cache);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process an event, which can update packets-in-flight not trivially.
|
|
|
|
|
* Main goal of this function is to calculate new estimate for left_out,
|
|
|
|
|
* taking into account both packets sitting in receiver's buffer and
|
|
|
|
@ -2792,19 +2741,17 @@ static void tcp_rack_identify_loss(struct sock *sk, int *ack_flag)
|
|
|
|
|
* It does _not_ decide what to send, it is made in function
|
|
|
|
|
* tcp_xmit_retransmit_queue().
|
|
|
|
|
*/
|
|
|
|
|
static void tcp_fastretrans_alert(struct sock *sk, const int acked,
|
|
|
|
|
static void tcp_fastretrans_alert(struct sock *sk, const u32 prior_snd_una,
|
|
|
|
|
bool is_dupack, int *ack_flag, int *rexmit)
|
|
|
|
|
{
|
|
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
int fast_rexmit = 0, flag = *ack_flag;
|
|
|
|
|
bool do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) &&
|
|
|
|
|
(tcp_fackets_out(tp) > tp->reordering));
|
|
|
|
|
tcp_force_fast_retransmit(sk));
|
|
|
|
|
|
|
|
|
|
if (!tp->packets_out && tp->sacked_out)
|
|
|
|
|
tp->sacked_out = 0;
|
|
|
|
|
if (!tp->sacked_out && tp->fackets_out)
|
|
|
|
|
tp->fackets_out = 0;
|
|
|
|
|
|
|
|
|
|
/* Now state machine starts.
|
|
|
|
|
* A. ECE, hence prohibit cwnd undoing, the reduction is required. */
|
|
|
|
@ -2851,11 +2798,11 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
|
|
|
|
|
if (tcp_is_reno(tp) && is_dupack)
|
|
|
|
|
tcp_add_reno_sack(sk);
|
|
|
|
|
} else {
|
|
|
|
|
if (tcp_try_undo_partial(sk, acked))
|
|
|
|
|
if (tcp_try_undo_partial(sk, prior_snd_una))
|
|
|
|
|
return;
|
|
|
|
|
/* Partial ACK arrived. Force fast retransmit. */
|
|
|
|
|
do_lost = tcp_is_reno(tp) ||
|
|
|
|
|
tcp_fackets_out(tp) > tp->reordering;
|
|
|
|
|
tcp_force_fast_retransmit(sk);
|
|
|
|
|
}
|
|
|
|
|
if (tcp_try_undo_dsack(sk)) {
|
|
|
|
|
tcp_try_keep_open(sk);
|
|
|
|
@ -3065,15 +3012,15 @@ static void tcp_ack_tstamp(struct sock *sk, struct sk_buff *skb,
|
|
|
|
|
* is before the ack sequence we can discard it as it's confirmed to have
|
|
|
|
|
* arrived at the other end.
|
|
|
|
|
*/
|
|
|
|
|
static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
|
|
|
|
|
u32 prior_snd_una, int *acked,
|
|
|
|
|
static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack,
|
|
|
|
|
u32 prior_snd_una,
|
|
|
|
|
struct tcp_sacktag_state *sack)
|
|
|
|
|
{
|
|
|
|
|
const struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
|
u64 first_ackt, last_ackt;
|
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
|
u32 prior_sacked = tp->sacked_out;
|
|
|
|
|
u32 reord = tp->packets_out;
|
|
|
|
|
u32 reord = tp->snd_nxt; /* lowest acked un-retx un-sacked seq */
|
|
|
|
|
struct sk_buff *skb, *next;
|
|
|
|
|
bool fully_acked = true;
|
|
|
|
|
long sack_rtt_us = -1L;
|
|
|
|
@ -3088,6 +3035,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
|
|
|
|
|
|
|
|
|
|
for (skb = skb_rb_first(&sk->tcp_rtx_queue); skb; skb = next) {
|
|
|
|
|
struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
|
|
|
|
|
const u32 start_seq = scb->seq;
|
|
|
|
|
u8 sacked = scb->sacked;
|
|
|
|
|
u32 acked_pcount;
|
|
|
|
|
|
|
|
|
@ -3118,7 +3066,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
|
|
|
|
|
first_ackt = last_ackt;
|
|
|
|
|
|
|
|
|
|
last_in_flight = TCP_SKB_CB(skb)->tx.in_flight;
|
|
|
|
|
reord = min(pkts_acked, reord);
|
|
|
|
|
if (before(start_seq, reord))
|
|
|
|
|
reord = start_seq;
|
|
|
|
|
if (!after(scb->end_seq, tp->high_seq))
|
|
|
|
|
flag |= FLAG_ORIG_SACK_ACKED;
|
|
|
|
|
}
|
|
|
|
@ -3196,16 +3145,12 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
|
|
|
|
|
int delta;
|
|
|
|
|
|
|
|
|
|
/* Non-retransmitted hole got filled? That's reordering */
|
|
|
|
|
if (reord < prior_fackets && reord <= tp->fackets_out)
|
|
|
|
|
tcp_update_reordering(sk, tp->fackets_out - reord, 0);
|
|
|
|
|
if (before(reord, prior_fack))
|
|
|
|
|
tcp_check_sack_reordering(sk, reord, 0);
|
|
|
|
|
|
|
|
|
|
delta = tcp_is_fack(tp) ? pkts_acked :
|
|
|
|
|
prior_sacked - tp->sacked_out;
|
|
|
|
|
delta = prior_sacked - tp->sacked_out;
|
|
|
|
|
tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tp->fackets_out -= min(pkts_acked, tp->fackets_out);
|
|
|
|
|
|
|
|
|
|
} else if (skb && rtt_update && sack_rtt_us >= 0 &&
|
|
|
|
|
sack_rtt_us > tcp_stamp_us_delta(tp->tcp_mstamp, skb->skb_mstamp)) {
|
|
|
|
|
/* Do not re-arm RTO if the sack RTT is measured from data sent
|
|
|
|
@ -3246,7 +3191,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
*acked = pkts_acked;
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3555,12 +3499,11 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
|
|
|
|
u32 ack_seq = TCP_SKB_CB(skb)->seq;
|
|
|
|
|
u32 ack = TCP_SKB_CB(skb)->ack_seq;
|
|
|
|
|
bool is_dupack = false;
|
|
|
|
|
u32 prior_fackets;
|
|
|
|
|
int prior_packets = tp->packets_out;
|
|
|
|
|
u32 delivered = tp->delivered;
|
|
|
|
|
u32 lost = tp->lost;
|
|
|
|
|
int acked = 0; /* Number of packets newly acked */
|
|
|
|
|
int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */
|
|
|
|
|
u32 prior_fack;
|
|
|
|
|
|
|
|
|
|
sack_state.first_sackt = 0;
|
|
|
|
|
sack_state.rate = &rs;
|
|
|
|
@ -3592,7 +3535,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
|
|
|
|
icsk->icsk_retransmits = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prior_fackets = tp->fackets_out;
|
|
|
|
|
prior_fack = tcp_highest_sack_seq(tp);
|
|
|
|
|
rs.prior_in_flight = tcp_packets_in_flight(tp);
|
|
|
|
|
|
|
|
|
|
/* ts_recent update must be made after we are sure that the packet
|
|
|
|
@ -3648,8 +3591,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
|
|
|
|
goto no_queue;
|
|
|
|
|
|
|
|
|
|
/* See if we can take anything off of the retransmit queue. */
|
|
|
|
|
flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, &acked,
|
|
|
|
|
&sack_state);
|
|
|
|
|
flag |= tcp_clean_rtx_queue(sk, prior_fack, prior_snd_una, &sack_state);
|
|
|
|
|
|
|
|
|
|
tcp_rack_update_reo_wnd(sk, &rs);
|
|
|
|
|
|
|
|
|
@ -3661,7 +3603,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
|
|
|
|
|
|
|
|
|
if (tcp_ack_is_dubious(sk, flag)) {
|
|
|
|
|
is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
|
|
|
|
|
tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);
|
|
|
|
|
tcp_fastretrans_alert(sk, prior_snd_una, is_dupack, &flag,
|
|
|
|
|
&rexmit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
|
|
|
|
@ -3677,7 +3620,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
|
|
|
|
no_queue:
|
|
|
|
|
/* If data was DSACKed, see if we can undo a cwnd reduction. */
|
|
|
|
|
if (flag & FLAG_DSACKING_ACK)
|
|
|
|
|
tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);
|
|
|
|
|
tcp_fastretrans_alert(sk, prior_snd_una, is_dupack, &flag,
|
|
|
|
|
&rexmit);
|
|
|
|
|
/* If this ack opens up a zero window, clear backoff. It was
|
|
|
|
|
* being used to time the probes, and is probably far higher than
|
|
|
|
|
* it needs to be for normal retransmission.
|
|
|
|
@ -3699,7 +3643,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
|
|
|
|
if (TCP_SKB_CB(skb)->sacked) {
|
|
|
|
|
flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
|
|
|
|
|
&sack_state);
|
|
|
|
|
tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);
|
|
|
|
|
tcp_fastretrans_alert(sk, prior_snd_una, is_dupack, &flag,
|
|
|
|
|
&rexmit);
|
|
|
|
|
tcp_xmit_recovery(sk, rexmit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -5708,9 +5653,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
|
|
|
|
|
tp->tcp_header_len = sizeof(struct tcphdr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_fack)
|
|
|
|
|
tcp_enable_fack(tp);
|
|
|
|
|
|
|
|
|
|
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
|
|
|
|
|
tcp_initialize_rcv_mss(sk);
|
|
|
|
|
|
|
|
|
|