Skip to content

Commit bd1fdf8

Browse files
committed
rxrpc: Add a timeout for detecting lost ACKs/lost DATA
Add an extra timeout that is set/updated when we send a DATA packet that has the request-ack flag set. This allows us to detect if we don't get an ACK in response to the latest flagged packet. The ACK packet is adjudged to have been lost if it doesn't turn up within 2*RTT of the transmission. If the timeout occurs, we schedule the sending of a PING ACK to find out the state of the other side. If a new DATA packet is ready to go sooner, we cancel the sending of the ping and set the request-ack flag on that instead. If we get back a PING-RESPONSE ACK that indicates a lower tx_top than what we had at the time of the ping transmission, we adjudge all the DATA packets sent between the response tx_top and the ping-time tx_top to have been lost and retransmit immediately. Rather than sending a PING ACK, we could just pick a DATA packet and speculatively retransmit that with request-ack set. It should result in either a REQUESTED ACK or a DUPLICATE ACK which we can then use in lieu the a PING-RESPONSE ACK mentioned above. Signed-off-by: David Howells <[email protected]>
1 parent beb8e5e commit bd1fdf8

File tree

8 files changed

+98
-12
lines changed

8 files changed

+98
-12
lines changed

include/trace/events/rxrpc.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ enum rxrpc_timer_trace {
141141
rxrpc_timer_exp_ack,
142142
rxrpc_timer_exp_hard,
143143
rxrpc_timer_exp_idle,
144+
rxrpc_timer_exp_lost_ack,
144145
rxrpc_timer_exp_normal,
145146
rxrpc_timer_exp_ping,
146147
rxrpc_timer_exp_resend,
@@ -151,6 +152,7 @@ enum rxrpc_timer_trace {
151152
rxrpc_timer_set_for_ack,
152153
rxrpc_timer_set_for_hard,
153154
rxrpc_timer_set_for_idle,
155+
rxrpc_timer_set_for_lost_ack,
154156
rxrpc_timer_set_for_normal,
155157
rxrpc_timer_set_for_ping,
156158
rxrpc_timer_set_for_resend,
@@ -309,6 +311,7 @@ enum rxrpc_congest_change {
309311
EM(rxrpc_timer_exp_ack, "ExpAck") \
310312
EM(rxrpc_timer_exp_hard, "ExpHrd") \
311313
EM(rxrpc_timer_exp_idle, "ExpIdl") \
314+
EM(rxrpc_timer_exp_lost_ack, "ExpLoA") \
312315
EM(rxrpc_timer_exp_normal, "ExpNml") \
313316
EM(rxrpc_timer_exp_ping, "ExpPng") \
314317
EM(rxrpc_timer_exp_resend, "ExpRsn") \
@@ -318,6 +321,7 @@ enum rxrpc_congest_change {
318321
EM(rxrpc_timer_set_for_ack, "SetAck") \
319322
EM(rxrpc_timer_set_for_hard, "SetHrd") \
320323
EM(rxrpc_timer_set_for_idle, "SetIdl") \
324+
EM(rxrpc_timer_set_for_lost_ack, "SetLoA") \
321325
EM(rxrpc_timer_set_for_normal, "SetNml") \
322326
EM(rxrpc_timer_set_for_ping, "SetPng") \
323327
EM(rxrpc_timer_set_for_resend, "SetRTx") \
@@ -961,6 +965,7 @@ TRACE_EVENT(rxrpc_timer,
961965
__field(enum rxrpc_timer_trace, why )
962966
__field(long, now )
963967
__field(long, ack_at )
968+
__field(long, ack_lost_at )
964969
__field(long, resend_at )
965970
__field(long, ping_at )
966971
__field(long, expect_rx_by )
@@ -974,17 +979,19 @@ TRACE_EVENT(rxrpc_timer,
974979
__entry->why = why;
975980
__entry->now = now;
976981
__entry->ack_at = call->ack_at;
982+
__entry->ack_lost_at = call->ack_lost_at;
977983
__entry->resend_at = call->resend_at;
978984
__entry->expect_rx_by = call->expect_rx_by;
979985
__entry->expect_req_by = call->expect_req_by;
980986
__entry->expect_term_by = call->expect_term_by;
981987
__entry->timer = call->timer.expires;
982988
),
983989

984-
TP_printk("c=%p %s a=%ld r=%ld xr=%ld xq=%ld xt=%ld t=%ld",
990+
TP_printk("c=%p %s a=%ld la=%ld r=%ld xr=%ld xq=%ld xt=%ld t=%ld",
985991
__entry->call,
986992
__print_symbolic(__entry->why, rxrpc_timer_traces),
987993
__entry->ack_at - __entry->now,
994+
__entry->ack_lost_at - __entry->now,
988995
__entry->resend_at - __entry->now,
989996
__entry->expect_rx_by - __entry->now,
990997
__entry->expect_req_by - __entry->now,
@@ -1105,7 +1112,7 @@ TRACE_EVENT(rxrpc_congest,
11051112
memcpy(&__entry->sum, summary, sizeof(__entry->sum));
11061113
),
11071114

1108-
TP_printk("c=%p %08x %s %08x %s cw=%u ss=%u nr=%u,%u nw=%u,%u r=%u b=%u u=%u d=%u l=%x%s%s%s",
1115+
TP_printk("c=%p r=%08x %s q=%08x %s cw=%u ss=%u nr=%u,%u nw=%u,%u r=%u b=%u u=%u d=%u l=%x%s%s%s",
11091116
__entry->call,
11101117
__entry->ack_serial,
11111118
__print_symbolic(__entry->sum.ack_reason, rxrpc_ack_names),

net/rxrpc/ar-internal.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ enum rxrpc_call_event {
471471
RXRPC_CALL_EV_RESEND, /* Tx resend required */
472472
RXRPC_CALL_EV_PING, /* Ping send required */
473473
RXRPC_CALL_EV_EXPIRED, /* Expiry occurred */
474+
RXRPC_CALL_EV_ACK_LOST, /* ACK may be lost, send ping */
474475
};
475476

476477
/*
@@ -515,6 +516,7 @@ struct rxrpc_call {
515516
struct rxrpc_sock __rcu *socket; /* socket responsible */
516517
struct mutex user_mutex; /* User access mutex */
517518
unsigned long ack_at; /* When deferred ACK needs to happen */
519+
unsigned long ack_lost_at; /* When ACK is figured as lost */
518520
unsigned long resend_at; /* When next resend needs to happen */
519521
unsigned long ping_at; /* When next to send a ping */
520522
unsigned long expect_rx_by; /* When we expect to get a packet by */
@@ -624,6 +626,8 @@ struct rxrpc_call {
624626
ktime_t acks_latest_ts; /* Timestamp of latest ACK received */
625627
rxrpc_serial_t acks_latest; /* serial number of latest ACK received */
626628
rxrpc_seq_t acks_lowest_nak; /* Lowest NACK in the buffer (or ==tx_hard_ack) */
629+
rxrpc_seq_t acks_lost_top; /* tx_top at the time lost-ack ping sent */
630+
rxrpc_serial_t acks_lost_ping; /* Serial number of probe ACK */
627631
};
628632

629633
/*
@@ -1011,7 +1015,7 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net)
10111015
/*
10121016
* output.c
10131017
*/
1014-
int rxrpc_send_ack_packet(struct rxrpc_call *, bool);
1018+
int rxrpc_send_ack_packet(struct rxrpc_call *, bool, rxrpc_serial_t *);
10151019
int rxrpc_send_abort_packet(struct rxrpc_call *);
10161020
int rxrpc_send_data_packet(struct rxrpc_call *, struct sk_buff *, bool);
10171021
void rxrpc_reject_packets(struct rxrpc_local *);

net/rxrpc/call_event.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
245245
goto out;
246246
rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
247247
rxrpc_propose_ack_ping_for_lost_ack);
248-
rxrpc_send_ack_packet(call, true);
248+
rxrpc_send_ack_packet(call, true, NULL);
249249
goto out;
250250
}
251251

@@ -310,6 +310,7 @@ void rxrpc_process_call(struct work_struct *work)
310310
{
311311
struct rxrpc_call *call =
312312
container_of(work, struct rxrpc_call, processor);
313+
rxrpc_serial_t *send_ack;
313314
unsigned long now, next, t;
314315

315316
rxrpc_see_call(call);
@@ -358,6 +359,13 @@ void rxrpc_process_call(struct work_struct *work)
358359
set_bit(RXRPC_CALL_EV_ACK, &call->events);
359360
}
360361

362+
t = READ_ONCE(call->ack_lost_at);
363+
if (time_after_eq(now, t)) {
364+
trace_rxrpc_timer(call, rxrpc_timer_exp_lost_ack, now);
365+
cmpxchg(&call->ack_lost_at, t, now + MAX_JIFFY_OFFSET);
366+
set_bit(RXRPC_CALL_EV_ACK_LOST, &call->events);
367+
}
368+
361369
t = READ_ONCE(call->ping_at);
362370
if (time_after_eq(now, t)) {
363371
trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now);
@@ -379,15 +387,24 @@ void rxrpc_process_call(struct work_struct *work)
379387
goto recheck_state;
380388
}
381389

382-
if (test_and_clear_bit(RXRPC_CALL_EV_ACK, &call->events)) {
390+
send_ack = NULL;
391+
if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) {
392+
call->acks_lost_top = call->tx_top;
393+
rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
394+
rxrpc_propose_ack_ping_for_lost_ack);
395+
send_ack = &call->acks_lost_ping;
396+
}
397+
398+
if (test_and_clear_bit(RXRPC_CALL_EV_ACK, &call->events) ||
399+
send_ack) {
383400
if (call->ackr_reason) {
384-
rxrpc_send_ack_packet(call, false);
401+
rxrpc_send_ack_packet(call, false, send_ack);
385402
goto recheck_state;
386403
}
387404
}
388405

389406
if (test_and_clear_bit(RXRPC_CALL_EV_PING, &call->events)) {
390-
rxrpc_send_ack_packet(call, true);
407+
rxrpc_send_ack_packet(call, true, NULL);
391408
goto recheck_state;
392409
}
393410

@@ -404,6 +421,7 @@ void rxrpc_process_call(struct work_struct *work)
404421
set(call->expect_req_by);
405422
set(call->expect_term_by);
406423
set(call->ack_at);
424+
set(call->ack_lost_at);
407425
set(call->resend_at);
408426
set(call->ping_at);
409427

net/rxrpc/call_object.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ static void rxrpc_start_call_timer(struct rxrpc_call *call)
197197
unsigned long j = now + MAX_JIFFY_OFFSET;
198198

199199
call->ack_at = j;
200+
call->ack_lost_at = j;
200201
call->resend_at = j;
201202
call->ping_at = j;
202203
call->expect_rx_by = j;

net/rxrpc/input.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,43 @@ static void rxrpc_input_requested_ack(struct rxrpc_call *call,
630630
orig_serial, ack_serial, sent_at, resp_time);
631631
}
632632

633+
/*
634+
* Process the response to a ping that we sent to find out if we lost an ACK.
635+
*
636+
* If we got back a ping response that indicates a lower tx_top than what we
637+
* had at the time of the ping transmission, we adjudge all the DATA packets
638+
* sent between the response tx_top and the ping-time tx_top to have been lost.
639+
*/
640+
static void rxrpc_input_check_for_lost_ack(struct rxrpc_call *call)
641+
{
642+
rxrpc_seq_t top, bottom, seq;
643+
bool resend = false;
644+
645+
spin_lock_bh(&call->lock);
646+
647+
bottom = call->tx_hard_ack + 1;
648+
top = call->acks_lost_top;
649+
if (before(bottom, top)) {
650+
for (seq = bottom; before_eq(seq, top); seq++) {
651+
int ix = seq & RXRPC_RXTX_BUFF_MASK;
652+
u8 annotation = call->rxtx_annotations[ix];
653+
u8 anno_type = annotation & RXRPC_TX_ANNO_MASK;
654+
655+
if (anno_type != RXRPC_TX_ANNO_UNACK)
656+
continue;
657+
annotation &= ~RXRPC_TX_ANNO_MASK;
658+
annotation |= RXRPC_TX_ANNO_RETRANS;
659+
call->rxtx_annotations[ix] = annotation;
660+
resend = true;
661+
}
662+
}
663+
664+
spin_unlock_bh(&call->lock);
665+
666+
if (resend && !test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events))
667+
rxrpc_queue_call(call);
668+
}
669+
633670
/*
634671
* Process a ping response.
635672
*/
@@ -645,6 +682,9 @@ static void rxrpc_input_ping_response(struct rxrpc_call *call,
645682
smp_rmb();
646683
ping_serial = call->ping_serial;
647684

685+
if (orig_serial == call->acks_lost_ping)
686+
rxrpc_input_check_for_lost_ack(call);
687+
648688
if (!test_bit(RXRPC_CALL_PINGING, &call->flags) ||
649689
before(orig_serial, ping_serial))
650690
return;

net/rxrpc/output.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
9595
/*
9696
* Send an ACK call packet.
9797
*/
98-
int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping)
98+
int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
99+
rxrpc_serial_t *_serial)
99100
{
100101
struct rxrpc_connection *conn = NULL;
101102
struct rxrpc_ack_buffer *pkt;
@@ -165,6 +166,8 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping)
165166
ntohl(pkt->ack.firstPacket),
166167
ntohl(pkt->ack.serial),
167168
pkt->ack.reason, pkt->ack.nAcks);
169+
if (_serial)
170+
*_serial = serial;
168171

169172
if (ping) {
170173
call->ping_serial = serial;
@@ -323,7 +326,8 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
323326
* ACKs if a DATA packet appears to have been lost.
324327
*/
325328
if (!(sp->hdr.flags & RXRPC_LAST_PACKET) &&
326-
(retrans ||
329+
(test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events) ||
330+
retrans ||
327331
call->cong_mode == RXRPC_CALL_SLOW_START ||
328332
(call->peer->rtt_usage < 3 && sp->hdr.seq & 1) ||
329333
ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000),
@@ -370,6 +374,18 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
370374
if (whdr.flags & RXRPC_REQUEST_ACK) {
371375
call->peer->rtt_last_req = now;
372376
trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_data, serial);
377+
if (call->peer->rtt_usage > 1) {
378+
unsigned long nowj = jiffies, ack_lost_at;
379+
380+
ack_lost_at = nsecs_to_jiffies(2 * call->peer->rtt);
381+
if (ack_lost_at < 1)
382+
ack_lost_at = 1;
383+
384+
ack_lost_at += nowj;
385+
WRITE_ONCE(call->ack_lost_at, ack_lost_at);
386+
rxrpc_reduce_call_timer(call, ack_lost_at, nowj,
387+
rxrpc_timer_set_for_lost_ack);
388+
}
373389
}
374390
}
375391
_leave(" = %d [%u]", ret, call->peer->maxdata);

net/rxrpc/recvmsg.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
148148
if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) {
149149
rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, 0, serial, true, false,
150150
rxrpc_propose_ack_terminal_ack);
151-
rxrpc_send_ack_packet(call, false);
151+
rxrpc_send_ack_packet(call, false, NULL);
152152
}
153153
#endif
154154

@@ -222,7 +222,7 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
222222
true, true,
223223
rxrpc_propose_ack_rotate_rx);
224224
if (call->ackr_reason && call->ackr_reason != RXRPC_ACK_DELAY)
225-
rxrpc_send_ack_packet(call, false);
225+
rxrpc_send_ack_packet(call, false, NULL);
226226
}
227227
}
228228

net/rxrpc/sendmsg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
285285
do {
286286
/* Check to see if there's a ping ACK to reply to. */
287287
if (call->ackr_reason == RXRPC_ACK_PING_RESPONSE)
288-
rxrpc_send_ack_packet(call, false);
288+
rxrpc_send_ack_packet(call, false, NULL);
289289

290290
if (!skb) {
291291
size_t size, chunk, max, space;

0 commit comments

Comments
 (0)