Commit 50235c4b authored by David Howells's avatar David Howells

rxrpc: Obtain RTT data by requesting ACKs on DATA packets

In addition to sending a PING ACK to gain RTT data, we can set the
RXRPC_REQUEST_ACK flag on a DATA packet and get a REQUESTED-ACK ACK.  The
ACK packet contains the serial number of the packet it is in response to,
so we can look through the Tx buffer for a matching DATA packet.

This requires that the data packets be stamped with the time of
transmission as a ktime rather than having the resend_at time in jiffies.

This further requires the resend code to do the resend determination in
ktimes and convert to jiffies to set the timer.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 77f2efcb
...@@ -142,10 +142,7 @@ struct rxrpc_host_header { ...@@ -142,10 +142,7 @@ struct rxrpc_host_header {
*/ */
struct rxrpc_skb_priv { struct rxrpc_skb_priv {
union { union {
unsigned long resend_at; /* time in jiffies at which to resend */ u8 nr_jumbo; /* Number of jumbo subpackets */
struct {
u8 nr_jumbo; /* Number of jumbo subpackets */
};
}; };
union { union {
unsigned int offset; /* offset into buffer of next read */ unsigned int offset; /* offset into buffer of next read */
...@@ -663,6 +660,7 @@ extern const char rxrpc_recvmsg_traces[rxrpc_recvmsg__nr_trace][5]; ...@@ -663,6 +660,7 @@ extern const char rxrpc_recvmsg_traces[rxrpc_recvmsg__nr_trace][5];
enum rxrpc_rtt_tx_trace { enum rxrpc_rtt_tx_trace {
rxrpc_rtt_tx_ping, rxrpc_rtt_tx_ping,
rxrpc_rtt_tx_data,
rxrpc_rtt_tx__nr_trace rxrpc_rtt_tx__nr_trace
}; };
...@@ -670,6 +668,7 @@ extern const char rxrpc_rtt_tx_traces[rxrpc_rtt_tx__nr_trace][5]; ...@@ -670,6 +668,7 @@ extern const char rxrpc_rtt_tx_traces[rxrpc_rtt_tx__nr_trace][5];
enum rxrpc_rtt_rx_trace { enum rxrpc_rtt_rx_trace {
rxrpc_rtt_rx_ping_response, rxrpc_rtt_rx_ping_response,
rxrpc_rtt_rx_requested_ack,
rxrpc_rtt_rx__nr_trace rxrpc_rtt_rx__nr_trace
}; };
......
...@@ -142,12 +142,14 @@ static void rxrpc_resend(struct rxrpc_call *call) ...@@ -142,12 +142,14 @@ static void rxrpc_resend(struct rxrpc_call *call)
struct rxrpc_skb_priv *sp; struct rxrpc_skb_priv *sp;
struct sk_buff *skb; struct sk_buff *skb;
rxrpc_seq_t cursor, seq, top; rxrpc_seq_t cursor, seq, top;
unsigned long resend_at, now; ktime_t now = ktime_get_real(), max_age, oldest, resend_at;
int ix; int ix;
u8 annotation, anno_type; u8 annotation, anno_type;
_enter("{%d,%d}", call->tx_hard_ack, call->tx_top); _enter("{%d,%d}", call->tx_hard_ack, call->tx_top);
max_age = ktime_sub_ms(now, rxrpc_resend_timeout);
spin_lock_bh(&call->lock); spin_lock_bh(&call->lock);
cursor = call->tx_hard_ack; cursor = call->tx_hard_ack;
...@@ -160,8 +162,7 @@ static void rxrpc_resend(struct rxrpc_call *call) ...@@ -160,8 +162,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
* the packets in the Tx buffer we're going to resend and what the new * the packets in the Tx buffer we're going to resend and what the new
* resend timeout will be. * resend timeout will be.
*/ */
now = jiffies; oldest = now;
resend_at = now + rxrpc_resend_timeout;
for (seq = cursor + 1; before_eq(seq, top); seq++) { for (seq = cursor + 1; before_eq(seq, top); seq++) {
ix = seq & RXRPC_RXTX_BUFF_MASK; ix = seq & RXRPC_RXTX_BUFF_MASK;
annotation = call->rxtx_annotations[ix]; annotation = call->rxtx_annotations[ix];
...@@ -175,9 +176,9 @@ static void rxrpc_resend(struct rxrpc_call *call) ...@@ -175,9 +176,9 @@ static void rxrpc_resend(struct rxrpc_call *call)
sp = rxrpc_skb(skb); sp = rxrpc_skb(skb);
if (anno_type == RXRPC_TX_ANNO_UNACK) { if (anno_type == RXRPC_TX_ANNO_UNACK) {
if (time_after(sp->resend_at, now)) { if (ktime_after(skb->tstamp, max_age)) {
if (time_before(sp->resend_at, resend_at)) if (ktime_before(skb->tstamp, oldest))
resend_at = sp->resend_at; oldest = skb->tstamp;
continue; continue;
} }
} }
...@@ -186,7 +187,8 @@ static void rxrpc_resend(struct rxrpc_call *call) ...@@ -186,7 +187,8 @@ static void rxrpc_resend(struct rxrpc_call *call)
call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS | annotation; call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS | annotation;
} }
call->resend_at = resend_at; resend_at = ktime_sub(ktime_add_ns(oldest, rxrpc_resend_timeout), now);
call->resend_at = jiffies + nsecs_to_jiffies(ktime_to_ns(resend_at));
/* Now go through the Tx window and perform the retransmissions. We /* Now go through the Tx window and perform the retransmissions. We
* have to drop the lock for each send. If an ACK comes in whilst the * have to drop the lock for each send. If an ACK comes in whilst the
...@@ -205,15 +207,12 @@ static void rxrpc_resend(struct rxrpc_call *call) ...@@ -205,15 +207,12 @@ static void rxrpc_resend(struct rxrpc_call *call)
spin_unlock_bh(&call->lock); spin_unlock_bh(&call->lock);
if (rxrpc_send_data_packet(call, skb) < 0) { if (rxrpc_send_data_packet(call, skb) < 0) {
call->resend_at = now + 2;
rxrpc_free_skb(skb, rxrpc_skb_tx_freed); rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
return; return;
} }
if (rxrpc_is_client_call(call)) if (rxrpc_is_client_call(call))
rxrpc_expose_client_call(call); rxrpc_expose_client_call(call);
sp = rxrpc_skb(skb);
sp->resend_at = now + rxrpc_resend_timeout;
rxrpc_free_skb(skb, rxrpc_skb_tx_freed); rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
spin_lock_bh(&call->lock); spin_lock_bh(&call->lock);
......
...@@ -355,6 +355,38 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -355,6 +355,38 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,
_leave(" [queued]"); _leave(" [queued]");
} }
/*
* Process a requested ACK.
*/
static void rxrpc_input_requested_ack(struct rxrpc_call *call,
ktime_t resp_time,
rxrpc_serial_t orig_serial,
rxrpc_serial_t ack_serial)
{
struct rxrpc_skb_priv *sp;
struct sk_buff *skb;
ktime_t sent_at;
int ix;
for (ix = 0; ix < RXRPC_RXTX_BUFF_SIZE; ix++) {
skb = call->rxtx_buffer[ix];
if (!skb)
continue;
sp = rxrpc_skb(skb);
if (sp->hdr.serial != orig_serial)
continue;
smp_rmb();
sent_at = skb->tstamp;
goto found;
}
return;
found:
rxrpc_peer_add_rtt(call, rxrpc_rtt_rx_requested_ack,
orig_serial, ack_serial, sent_at, resp_time);
}
/* /*
* Process a ping response. * Process a ping response.
*/ */
...@@ -508,6 +540,9 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -508,6 +540,9 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE) if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE)
rxrpc_input_ping_response(call, skb->tstamp, acked_serial, rxrpc_input_ping_response(call, skb->tstamp, acked_serial,
sp->hdr.serial); sp->hdr.serial);
if (buf.ack.reason == RXRPC_ACK_REQUESTED)
rxrpc_input_requested_ack(call, skb->tstamp, acked_serial,
sp->hdr.serial);
if (buf.ack.reason == RXRPC_ACK_PING) { if (buf.ack.reason == RXRPC_ACK_PING) {
_proto("Rx ACK %%%u PING Request", sp->hdr.serial); _proto("Rx ACK %%%u PING Request", sp->hdr.serial);
......
...@@ -68,9 +68,9 @@ unsigned int rxrpc_rx_mtu = 5692; ...@@ -68,9 +68,9 @@ unsigned int rxrpc_rx_mtu = 5692;
unsigned int rxrpc_rx_jumbo_max = 4; unsigned int rxrpc_rx_jumbo_max = 4;
/* /*
* Time till packet resend (in jiffies). * Time till packet resend (in milliseconds).
*/ */
unsigned int rxrpc_resend_timeout = 4 * HZ; unsigned int rxrpc_resend_timeout = 4 * 1000;
const char *const rxrpc_pkts[] = { const char *const rxrpc_pkts[] = {
"?00", "?00",
...@@ -186,8 +186,10 @@ const char rxrpc_recvmsg_traces[rxrpc_recvmsg__nr_trace][5] = { ...@@ -186,8 +186,10 @@ const char rxrpc_recvmsg_traces[rxrpc_recvmsg__nr_trace][5] = {
const char rxrpc_rtt_tx_traces[rxrpc_rtt_tx__nr_trace][5] = { const char rxrpc_rtt_tx_traces[rxrpc_rtt_tx__nr_trace][5] = {
[rxrpc_rtt_tx_ping] = "PING", [rxrpc_rtt_tx_ping] = "PING",
[rxrpc_rtt_tx_data] = "DATA",
}; };
const char rxrpc_rtt_rx_traces[rxrpc_rtt_rx__nr_trace][5] = { const char rxrpc_rtt_rx_traces[rxrpc_rtt_rx__nr_trace][5] = {
[rxrpc_rtt_rx_ping_response] = "PONG", [rxrpc_rtt_rx_ping_response] = "PONG",
[rxrpc_rtt_rx_requested_ack] = "RACK",
}; };
...@@ -300,9 +300,12 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -300,9 +300,12 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb)
goto send_fragmentable; goto send_fragmentable;
done: done:
if (ret == 0) { if (ret >= 0) {
sp->resend_at = jiffies + rxrpc_resend_timeout; skb->tstamp = ktime_get_real();
smp_wmb();
sp->hdr.serial = serial; sp->hdr.serial = serial;
if (whdr.flags & RXRPC_REQUEST_ACK)
trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_data, serial);
} }
_leave(" = %d [%u]", ret, call->peer->maxdata); _leave(" = %d [%u]", ret, call->peer->maxdata);
return ret; return ret;
......
...@@ -137,7 +137,6 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -137,7 +137,6 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
if (seq == 1 && rxrpc_is_client_call(call)) if (seq == 1 && rxrpc_is_client_call(call))
rxrpc_expose_client_call(call); rxrpc_expose_client_call(call);
sp->resend_at = jiffies + rxrpc_resend_timeout;
ret = rxrpc_send_data_packet(call, skb); ret = rxrpc_send_data_packet(call, skb);
if (ret < 0) { if (ret < 0) {
_debug("need instant resend %d", ret); _debug("need instant resend %d", ret);
......
...@@ -59,7 +59,7 @@ static struct ctl_table rxrpc_sysctl_table[] = { ...@@ -59,7 +59,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
.data = &rxrpc_resend_timeout, .data = &rxrpc_resend_timeout,
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_ms_jiffies, .proc_handler = proc_dointvec,
.extra1 = (void *)&one, .extra1 = (void *)&one,
}, },
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment