// SPDX-License-Identifier: GPL-2.0-or-later /* Management of Tx window, Tx resend, ACKs and out-of-sequence reception * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/* * Propose a DELAY ACK be sent in the future.
*/ void rxrpc_propose_delay_ACK(struct rxrpc_call *call, rxrpc_serial_t serial, enum rxrpc_propose_ack_trace why)
{
ktime_t now = ktime_get_real(), delay;
/* * Resend the highest-seq DATA packet so far transmitted for RACK-TLP [RFC8985 7.3].
*/ void rxrpc_resend_tlp(struct rxrpc_call *call)
{ struct rxrpc_send_data_req req = {
.now = ktime_get_real(),
.seq = call->tx_transmitted,
.n = 1,
.tlp_probe = true,
.trace = rxrpc_txdata_tlp_retransmit,
};
/* There's a chance it'll be on the tail segment of the queue. */
req.tq = READ_ONCE(call->tx_qtail); if (req.tq &&
before(call->tx_transmitted, req.tq->qbase + RXRPC_NR_TXQUEUE)) {
rxrpc_retransmit_data(call, &req); return;
}
/* * Start transmitting the reply to a service. This cancels the need to ACK the * request if we haven't yet done so.
*/ staticvoid rxrpc_begin_service_reply(struct rxrpc_call *call)
{
rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SEND_REPLY); if (call->ackr_reason == RXRPC_ACK_DELAY)
call->ackr_reason = 0;
call->delay_ack_at = KTIME_MAX;
trace_rxrpc_timer_can(call, rxrpc_timer_trace_delayed_ack);
}
/* * Close the transmission phase. After this point there is no more data to be * transmitted in the call.
*/ staticvoid rxrpc_close_tx_phase(struct rxrpc_call *call)
{
_debug("________awaiting reply/ACK__________");
switch (__rxrpc_call_state(call)) { case RXRPC_CALL_CLIENT_SEND_REQUEST:
rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_REPLY); break; case RXRPC_CALL_SERVER_SEND_REPLY:
rxrpc_set_call_state(call, RXRPC_CALL_SERVER_AWAIT_ACK); break; default: break;
}
}
/* * Transmit some as-yet untransmitted data, to a maximum of the supplied limit.
*/ staticvoid rxrpc_transmit_fresh_data(struct rxrpc_call *call, unsignedint limit, enum rxrpc_txdata_trace trace)
{ int space = rxrpc_tx_window_space(call);
if (!test_bit(RXRPC_CALL_EXPOSED, &call->flags)) { if (call->send_top == call->tx_top) return;
rxrpc_expose_client_call(call);
}
/* Order send_top before the contents of the new txbufs and * txqueue pointers
*/
send_top = smp_load_acquire(&call->send_top); if (call->tx_top == send_top) break;
case RXRPC_CALL_SERVER_SEND_REPLY: case RXRPC_CALL_CLIENT_SEND_REQUEST: if (!rxrpc_tx_window_space(call)) return; if (call->tx_bottom == READ_ONCE(call->send_top)) {
rxrpc_inc_stat(call->rxnet, stat_tx_data_underflow); return;
}
rxrpc_transmit_fresh_data(call, limit, trace); break; default: return;
}
}
/* * Ping the other end to fill our RTT cache and to retrieve the rwind * and MTU parameters.
*/ staticvoid rxrpc_send_initial_ping(struct rxrpc_call *call)
{ if (call->rtt_count < 3 ||
ktime_before(ktime_add_ms(call->rtt_last_req, 1000),
ktime_get_real()))
rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_params);
}
t = ktime_sub(call->rack_timo_at, ktime_get_real()); if (t <= 0) {
trace_rxrpc_timer_exp(call, t,
rxrpc_timer_trace_rack_off + call->rack_timer_mode);
call->rack_timo_at = KTIME_MAX;
rxrpc_rack_timer_expired(call, t);
}
} while (!skb_queue_empty(&call->rx_queue));
/* If we see our async-event poke, check for timeout trippage. */
now = ktime_get_real();
t = ktime_sub(call->expect_rx_by, now); if (t <= 0) {
trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_expect_rx); goto expired;
}
t = ktime_sub(call->expect_req_by, now); if (t <= 0) {
call->expect_req_by = KTIME_MAX; if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST) {
trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_idle); goto expired;
}
}
t = ktime_sub(READ_ONCE(call->expect_term_by), now); if (t <= 0) {
trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_hard); goto expired;
}
t = ktime_sub(call->delay_ack_at, now); if (t <= 0) {
trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_delayed_ack);
call->delay_ack_at = KTIME_MAX;
rxrpc_send_ACK(call, RXRPC_ACK_DELAY, 0,
rxrpc_propose_ack_delayed_ack);
}
t = ktime_sub(call->ping_at, now); if (t <= 0) {
trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_ping);
call->ping_at = KTIME_MAX;
rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_keepalive);
}
now = ktime_get_real();
t = ktime_sub(call->keepalive_at, now); if (t <= 0) {
trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_keepalive);
call->keepalive_at = KTIME_MAX;
rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_keepalive);
}
if (test_and_clear_bit(RXRPC_CALL_EV_INITIAL_PING, &call->events))
rxrpc_send_initial_ping(call);
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.