Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -142,11 +142,8 @@ struct rxrpc_host_header {
 */
struct rxrpc_skb_priv {
	union {
		unsigned long	resend_at;	/* time in jiffies at which to resend */
		struct {
		u8		nr_jumbo;	/* Number of jumbo subpackets */
	};
	};
	union {
		unsigned int	offset;		/* offset into buffer of next read */
		int		remain;		/* amount of space remaining for next write */
@@ -663,6 +660,7 @@ extern const char rxrpc_recvmsg_traces[rxrpc_recvmsg__nr_trace][5];

enum rxrpc_rtt_tx_trace {
	rxrpc_rtt_tx_ping,
	rxrpc_rtt_tx_data,
	rxrpc_rtt_tx__nr_trace
};

@@ -670,6 +668,7 @@ extern const char rxrpc_rtt_tx_traces[rxrpc_rtt_tx__nr_trace][5];

enum rxrpc_rtt_rx_trace {
	rxrpc_rtt_rx_ping_response,
	rxrpc_rtt_rx_requested_ack,
	rxrpc_rtt_rx__nr_trace
};

+9 −10
Original line number Diff line number Diff line
@@ -142,12 +142,14 @@ static void rxrpc_resend(struct rxrpc_call *call)
	struct rxrpc_skb_priv *sp;
	struct sk_buff *skb;
	rxrpc_seq_t cursor, seq, top;
	unsigned long resend_at, now;
	ktime_t now = ktime_get_real(), max_age, oldest, resend_at;
	int ix;
	u8 annotation, anno_type;

	_enter("{%d,%d}", call->tx_hard_ack, call->tx_top);

	max_age = ktime_sub_ms(now, rxrpc_resend_timeout);

	spin_lock_bh(&call->lock);

	cursor = call->tx_hard_ack;
@@ -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
	 * resend timeout will be.
	 */
	now = jiffies;
	resend_at = now + rxrpc_resend_timeout;
	oldest = now;
	for (seq = cursor + 1; before_eq(seq, top); seq++) {
		ix = seq & RXRPC_RXTX_BUFF_MASK;
		annotation = call->rxtx_annotations[ix];
@@ -175,9 +176,9 @@ static void rxrpc_resend(struct rxrpc_call *call)
		sp = rxrpc_skb(skb);

		if (anno_type == RXRPC_TX_ANNO_UNACK) {
			if (time_after(sp->resend_at, now)) {
				if (time_before(sp->resend_at, resend_at))
					resend_at = sp->resend_at;
			if (ktime_after(skb->tstamp, max_age)) {
				if (ktime_before(skb->tstamp, oldest))
					oldest = skb->tstamp;
				continue;
			}
		}
@@ -186,7 +187,8 @@ static void rxrpc_resend(struct rxrpc_call *call)
		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
	 * 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)
		spin_unlock_bh(&call->lock);

		if (rxrpc_send_data_packet(call, skb) < 0) {
			call->resend_at = now + 2;
			rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
			return;
		}

		if (rxrpc_is_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);
		spin_lock_bh(&call->lock);
+35 −0
Original line number Diff line number Diff line
@@ -355,6 +355,38 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,
	_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.
 */
@@ -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)
		rxrpc_input_ping_response(call, skb->tstamp, acked_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) {
		_proto("Rx ACK %%%u PING Request", sp->hdr.serial);
+4 −2
Original line number Diff line number Diff line
@@ -68,9 +68,9 @@ unsigned int rxrpc_rx_mtu = 5692;
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[] = {
	"?00",
@@ -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] = {
	[rxrpc_rtt_tx_ping]		= "PING",
	[rxrpc_rtt_tx_data]		= "DATA",
};

const char rxrpc_rtt_rx_traces[rxrpc_rtt_rx__nr_trace][5] = {
	[rxrpc_rtt_rx_ping_response]	= "PONG",
	[rxrpc_rtt_rx_requested_ack]	= "RACK",
};
+5 −2
Original line number Diff line number Diff line
@@ -300,9 +300,12 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb)
		goto send_fragmentable;

done:
	if (ret == 0) {
		sp->resend_at = jiffies + rxrpc_resend_timeout;
	if (ret >= 0) {
		skb->tstamp = ktime_get_real();
		smp_wmb();
		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);
	return ret;
Loading