// SPDX-License-Identifier: GPL-2.0-or-later /* RxRPC packet transmission * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/* * Increase Tx backoff on transmission failure and clear it on success.
*/ staticvoid rxrpc_tx_backoff(struct rxrpc_call *call, int ret)
{ if (ret < 0) { if (call->tx_backoff < 1000)
call->tx_backoff += 100;
} else {
call->tx_backoff = 0;
}
}
/* * Arrange for a keepalive ping a certain time after we last transmitted. This * lets the far side know we're still interested in this call and helps keep * the route through any intervening firewall open. * * Receiving a response to the ping will prevent the ->expect_rx_by timer from * expiring.
*/ staticvoid rxrpc_set_keepalive(struct rxrpc_call *call, ktime_t now)
{
ktime_t delay = ms_to_ktime(READ_ONCE(call->next_rx_timo) / 6);
/* * Send an ACK probe for path MTU discovery.
*/ void rxrpc_send_probe_for_pmtud(struct rxrpc_call *call)
{
rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_mtu_probe);
}
/* * Send an ABORT call packet.
*/ int rxrpc_send_abort_packet(struct rxrpc_call *call)
{ struct rxrpc_connection *conn; struct rxrpc_abort_buffer pkt; struct msghdr msg; struct kvec iov[1];
rxrpc_serial_t serial; int ret;
/* Don't bother sending aborts for a client call once the server has * hard-ACK'd all of its request data. After that point, we're not * going to stop the operation proceeding, and whilst we might limit * the reply, it's not worth it if we can send a new call on the same * channel instead, thereby closing off this call.
*/ if (rxrpc_is_client_call(call) &&
test_bit(RXRPC_CALL_TX_ALL_ACKED, &call->flags)) return 0;
if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) return -ECONNRESET;
if (subpkt < req->n - 1) {
len = RXRPC_JUMBO_DATALEN; goto dont_set_request_ack;
}
/* If our RTT cache needs working on, request an ACK. Also request * ACKs if a DATA packet appears to have been lost. * * However, we mustn't request an ACK on the last reply packet of a * service call, lest OpenAFS incorrectly send us an ACK with some * soft-ACKs in it and then never follow up with a proper hard ACK.
*/ if (last && rxrpc_sending_to_client(txb))
why = rxrpc_reqack_no_srv_last; elseif (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events))
why = rxrpc_reqack_ack_lost; elseif (txb->flags & RXRPC_TXBUF_RESENT)
why = rxrpc_reqack_retrans; elseif (call->cong_ca_state == RXRPC_CA_SLOW_START && call->cong_cwnd <= RXRPC_MIN_CWND)
why = rxrpc_reqack_slow_start; elseif (call->tx_winsize <= 2)
why = rxrpc_reqack_small_txwin; elseif (call->rtt_count < 3)
why = rxrpc_reqack_more_rtt; elseif (ktime_before(ktime_add_ms(call->rtt_last_req, 1000), ktime_get_real()))
why = rxrpc_reqack_old_rtt; elseif (!last && !after(READ_ONCE(call->send_top), txb->seq))
why = rxrpc_reqack_app_stall; else goto dont_set_request_ack;
/* * Prepare a transmission queue object for initial transmission. Returns the * number of microseconds since the transmission queue base timestamp.
*/ staticunsignedint rxrpc_prepare_txqueue(struct rxrpc_txqueue *tq, struct rxrpc_send_data_req *req)
{ if (!tq) return 0; if (tq->xmit_ts_base == KTIME_MIN) {
tq->xmit_ts_base = req->now; return 0;
} return ktime_to_us(ktime_sub(req->now, tq->xmit_ts_base));
}
for (int i = 0;;) { int ix = seq & RXRPC_TXQ_MASK; struct rxrpc_txbuf *txb = tq->bufs[seq & RXRPC_TXQ_MASK];
_debug("prep[%u] tq=%x q=%x", i, tq->qbase, seq);
/* Record (re-)transmission for RACK [RFC8985 6.1]. */ if (__test_and_clear_bit(ix, &tq->segment_lost))
call->tx_nr_lost--; if (req->retrans) {
__set_bit(ix, &tq->ever_retransmitted);
__set_bit(ix, &tq->segment_retransmitted);
call->tx_nr_resent++;
} else {
call->tx_nr_sent++;
start_tlp = true;
}
tq->segment_xmit_ts[ix] = xmit_ts;
tq->segment_serial[ix] = serial; if (i + 1 == req->n) /* Only sample the last subpacket in a jumbo. */
__set_bit(ix, &tq->rtt_samples);
len += rxrpc_prepare_data_subpacket(call, req, txb, whdr, serial, i);
serial++;
seq++;
i++; if (i >= req->n) break; if (!(seq & RXRPC_TXQ_MASK)) {
tq = tq->next;
trace_rxrpc_tq(call, tq, seq, rxrpc_tq_transmit_advance);
xmit_ts = rxrpc_prepare_txqueue(tq, req);
}
}
/* Set timeouts */ if (req->tlp_probe) { /* Sending TLP loss probe [RFC8985 7.3]. */
call->tlp_serial = serial - 1;
call->tlp_seq = seq - 1;
} elseif (start_tlp) { /* Schedule TLP loss probe [RFC8985 7.2]. */
ktime_t pto;
if (!test_bit(RXRPC_CALL_BEGAN_RX_TIMER, &call->flags)) /* The first packet may take longer to elicit a response. */
pto = NSEC_PER_SEC; else
pto = rxrpc_tlp_calc_pto(call, req->now);
/* Send the packet with the don't fragment bit set unless we think it's * too big or if this is a retransmission.
*/ if (seq == call->tx_transmitted + 1 &&
len >= sizeof(struct rxrpc_wire_header) + call->peer->max_data) {
rxrpc_local_dont_fragment(conn->local, false);
frag = rxrpc_tx_point_call_data_frag;
} else {
rxrpc_local_dont_fragment(conn->local, true);
frag = rxrpc_tx_point_call_data_nofrag;
}
/* Track what we've attempted to transmit at least once so that the * retransmission algorithm doesn't try to resend what we haven't sent * yet.
*/ if (seq == call->tx_transmitted + 1)
call->tx_transmitted = seq + req->n - 1;
if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { staticint lose;
/* send the packet by UDP * - returns -EMSGSIZE if UDP would have to fragment the packet * to go out of the interface * - in which case, we'll have processed the ICMP error * message and update the peer record
*/
rxrpc_inc_stat(call->rxnet, stat_tx_data_send);
ret = do_udp_sendmsg(conn->local->socket, &msg, len);
conn->peer->last_tx_at = ktime_get_seconds();
if (ret < 0) { /* Cancel the call if the initial transmission fails or if we * hit due to network routing issues that aren't going away * anytime soon. The layer above can arrange the * retransmission.
*/ if (new_call ||
ret == -ENETUNREACH ||
ret == -EHOSTUNREACH ||
ret == -ECONNREFUSED)
rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
RX_USER_ABORT, ret);
}
/* * Send a VERSION reply to a peer as a keepalive.
*/ void rxrpc_send_keepalive(struct rxrpc_peer *peer)
{ struct rxrpc_wire_header whdr; struct msghdr msg; struct kvec iov[2];
size_t len; int ret;
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.