/* If peer does not open window for long time, or did not transmit
* anything for long time, penalize it. */ if ((s32)(tcp_jiffies32 - tp->lsndtime) > 2*tcp_rto_max(sk) || !do_reset)
shift++;
/* If some dubious ICMP arrived, penalize even more. */ if (READ_ONCE(sk->sk_err_soft))
shift++;
if (tcp_check_oom(sk, shift)) { /* Catch exceptional cases, when connection requires reset.
* 1. Last segment was sent recently. */ if ((s32)(tcp_jiffies32 - tp->lsndtime) <= TCP_TIMEWAIT_LEN || /* 2. Window is closed. */
(!tp->snd_wnd && !tp->packets_out))
do_reset = true; if (do_reset)
tcp_send_active_reset(sk, GFP_ATOMIC,
SK_RST_REASON_TCP_ABORT_ON_MEMORY);
tcp_done(sk);
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); return1;
}
if (!check_net(sock_net(sk))) { /* Not possible to send reset; just close */
tcp_done(sk); return1;
}
return0;
}
/** *tcp_orphan_retries()-Returnsmaximalnumberofretriesonanorphanedsocket *@sk:Pointertothecurrentsocket. *@alive:bool,socketalivestate
*/ staticint tcp_orphan_retries(struct sock *sk, bool alive)
{ int retries = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_orphan_retries); /* May be zero. */
/* We know from an ICMP that something is wrong. */ if (READ_ONCE(sk->sk_err_soft) && !alive)
retries = 0;
/* However, if socket sent something recently, select some safe *numberofretries.8correspondsto>100secondswithminimal
* RTO of 200msec. */ if (retries == 0 && alive)
retries = 8; return retries;
}
staticvoid tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
{ conststruct net *net = sock_net(sk); int mss;
/* Black hole detection */ if (!READ_ONCE(net->ipv4.sysctl_tcp_mtu_probing)) return;
/* Avoid taking socket spinlock if there is no ACK to send. *Thecompressed_ackcheckisracy,butaseparatehrtimer *willtakecareofiteventually.
*/ if (!(smp_load_acquire(&icsk->icsk_ack.pending) & ICSK_ACK_TIMER) &&
!READ_ONCE(tcp_sk(sk)->compressed_ack)) goto out;
bh_lock_sock(sk); if (!sock_owned_by_user(sk)) {
tcp_delack_timer_handler(sk);
} else {
__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); /* deleguate our work to tcp_release_cb() */ if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags))
sock_hold(sk);
}
bh_unlock_sock(sk);
out:
sock_put(sk);
}
max_probes = tcp_orphan_retries(sk, alive); if (!alive && icsk->icsk_backoff >= max_probes) goto abort; if (tcp_out_of_resources(sk, true)) return;
}
if (icsk->icsk_probes_out >= max_probes) {
abort: tcp_write_err(sk);
} else { /* Only send another probe if we didn't close things up. */
tcp_send_probe0(sk);
}
}
if (user_timeout) { /* If user application specified a TCP_USER_TIMEOUT, *itdoesnotwantwin0packetsto'resetthetimer' *whileretransmitsarenotmakingprogress.
*/ if (rtx_delta > user_timeout) returntrue;
timeout = min_t(u32, timeout, msecs_to_jiffies(user_timeout));
} /* Note: timer interrupt might have been delayed by at least one jiffy, *andtp->rcv_tstampmightverywellhavebeenwrittenrecently. *rcv_deltacanthusbenegative.
*/
rcv_delta = icsk_timeout(icsk) - tp->rcv_tstamp; if (rcv_delta <= timeout) returnfalse;
tcp_update_rto_stats(sk); if (tcp_retransmit_skb(sk, tcp_rtx_queue_head(sk), 1) > 0) { /* Retransmission failed because of local congestion, *Letsendersfightforlocalresourcesconservatively.
*/
tcp_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
TCP_RESOURCE_PROBE_INTERVAL, false); goto out;
}
/* Increase the timeout each time we retransmit. Note that *wedonotincreasetherttestimate.rtoisinitialized *fromrtt,butincreaseshere.Jacobson(SIGCOMM88)suggests *thatdoublingrtoeachtimeistheleastwecangetawaywith. *InKA9Q,Karnusesthisforthefirstfewtimes,andthen *goestoquadratic.netBSDdoubles,butonlygoesupto*64, *andclampsat1to64secafterwards.Notethat120secis *definedintheprotocolasthemaximumpossibleRTT.Iguess *we'llhavetousesomethingotherthanTCPtotalktothe *UniversityofMars. * *PAWSallowsuslongertimeoutsandlargewindows,soonce *implementedftptomarswillworknicely.Wewillhavetofix *the120secondclampsthough!
*/
out_reset_timer: /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is *usedtoresettimer,setto0.Recalculate'icsk_rto'asthis *mightbeincreasedifthestreamoscillatesbetweenthinandthick, *thustheoldvaluemightalreadybetoohighcomparedtothevalue *setby'tcp_set_rto'intcp_input.cwhichresetsthertowithout *backoff.LimittoTCP_THIN_LINEAR_RETRIESbeforeinitiating *exponentialbackoffbehaviourtoavoidcontinuehammering *linear-timeoutretransmissionsintoablackhole
*/ if (sk->sk_state == TCP_ESTABLISHED &&
(tp->thin_lto || READ_ONCE(net->ipv4.sysctl_tcp_thin_linear_timeouts)) &&
tcp_stream_is_thin(tp) &&
icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) {
icsk->icsk_backoff = 0;
icsk->icsk_rto = clamp(__tcp_set_rto(tp),
tcp_rto_min(sk),
tcp_rto_max(sk));
} elseif (sk->sk_state != TCP_SYN_SENT ||
tp->total_rto >
READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts)) { /* Use normal (exponential) backoff unless linear timeouts are *activated.
*/
icsk->icsk_backoff++;
icsk->icsk_rto = min(icsk->icsk_rto << 1, tcp_rto_max(sk));
}
tcp_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
tcp_clamp_rto_to_user_timeout(sk), false); if (retransmits_timed_out(sk, READ_ONCE(net->ipv4.sysctl_tcp_retries1) + 1, 0))
__sk_dst_reset(sk);
out:;
}
/* Called with bottom-half processing disabled. *Calledbytcp_write_timer()andtcp_release_cb().
*/ void tcp_write_timer_handler(struct sock *sk)
{ struct inet_connection_sock *icsk = inet_csk(sk); int event;
/* Only process if socket is not in use. */
bh_lock_sock(sk); if (sock_owned_by_user(sk)) { /* Try again later. */
tcp_reset_keepalive_timer(sk, HZ/20); goto out;
}
if (sk->sk_state == TCP_LISTEN) {
pr_err("Hmm... keepalive on a LISTEN ???\n"); goto out;
}
tcp_mstamp_refresh(tp); if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { if (READ_ONCE(tp->linger2) >= 0) { constint tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN;
bh_lock_sock(sk); if (!sock_owned_by_user(sk)) { if (tp->compressed_ack) { /* Since we have to send one ack finally, *subtractonefromtp->compressed_acktokeep *LINUX_MIB_TCPACKCOMPRESSEDaccurate.
*/
tp->compressed_ack--;
tcp_mstamp_refresh(tp);
tcp_send_ack(sk);
}
} else { if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED,
&sk->sk_tsq_flags))
sock_hold(sk);
}
bh_unlock_sock(sk);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.