History

rxrpc: Fix congestion management

rxrpc has a problem in its congestion management in that it saves the congestion window size (cwnd) from one call to another, but if this is 0 at the time is saved, then the next call may not actually manage to ever transmit anything. To this end: (1) Don't save cwnd between calls, but rather reset back down to the initial cwnd and re-enter slow-start if data transmission is idle for more than an RTT. (2) Preserve ssthresh instead, as that is a handy estimate of pipe capacity. Knowing roughly when to stop slow start and enter congestion avoidance can reduce the tendency to overshoot and drop larger amounts of packets when probing. In future, cwind growth also needs to be constrained when the window isn't being filled due to being application limited.

David Howells committed 4 years ago

Commit 1fc4fa21 parent 6869ddb11 files · +60 −20Browse files

Unified · Split

11 files
  1. include/trace/events/rxrpc.h +1 −0
  2. net/rxrpc/ar-internal.h +5 −4
  3. net/rxrpc/call_accept.c +2 −1
  4. net/rxrpc/call_object.c +6 −1
  5. net/rxrpc/conn_client.c +2 −1
  6. net/rxrpc/conn_object.c +1 −1
  7. net/rxrpc/input.c +20 −1
  8. net/rxrpc/output.c +1 −0
  9. net/rxrpc/peer_object.c +1 −6
  10. net/rxrpc/proc.c +2 −2
  11. net/rxrpc/sendmsg.c +19 −3
include/trace/events/rxrpc.h+1−0
@@ -193,6 +193,7 @@ · 192 unmodified lines
193 EM(rxrpc_cong_new_low_nack, " NewLowN") \193 EM(rxrpc_cong_new_low_nack, " NewLowN") \
194 EM(rxrpc_cong_no_change, " -") \194 EM(rxrpc_cong_no_change, " -") \
195 EM(rxrpc_cong_progress, " Progres") \195 EM(rxrpc_cong_progress, " Progres") \
196 EM(rxrpc_cong_idle_reset, " IdleRes") \
196 EM(rxrpc_cong_retransmit_again, " ReTxAgn") \197 EM(rxrpc_cong_retransmit_again, " ReTxAgn") \
197 EM(rxrpc_cong_rtt_window_end, " RttWinE") \198 EM(rxrpc_cong_rtt_window_end, " RttWinE") \
198 E_(rxrpc_cong_saw_nack, " SawNack")199 E_(rxrpc_cong_saw_nack, " SawNack")
net/rxrpc/ar-internal.h+5−4
@@ -332,7 +332,7 @@ struct rxrpc_peer { · 331 unmodified lines
332 u32 rto_j; /* Retransmission timeout in jiffies */332 u32 rto_j; /* Retransmission timeout in jiffies */
333 u8 backoff; /* Backoff timeout */333 u8 backoff; /* Backoff timeout */
334 334
335 u8 cong_cwnd; /* Congestion window size */335 u8 cong_ssthresh; /* Congestion slow-start threshold */
336};336};
337 337
338/*338/*
@@ -626,6 +626,7 @@ struct rxrpc_call { · 287 unmodified lines
626 u16 tx_backoff; /* Delay to insert due to Tx failure */626 u16 tx_backoff; /* Delay to insert due to Tx failure */
627 u8 tx_winsize; /* Maximum size of Tx window */627 u8 tx_winsize; /* Maximum size of Tx window */
628#define RXRPC_TX_MAX_WINDOW 128628#define RXRPC_TX_MAX_WINDOW 128
629 ktime_t tx_last_sent; /* Last time a transmission occurred */
629 630
630 /* Received data tracking */631 /* Received data tracking */
631 struct sk_buff_head recvmsg_queue; /* Queue of packets ready for recvmsg() */632 struct sk_buff_head recvmsg_queue; /* Queue of packets ready for recvmsg() */
@@ -687,10 +688,10 @@ struct rxrpc_call { · 55 unmodified lines
687 * Summary of a new ACK and the changes it made to the Tx buffer packet states.688 * Summary of a new ACK and the changes it made to the Tx buffer packet states.
688 */689 */
689struct rxrpc_ack_summary {690struct rxrpc_ack_summary {
691 u16 nr_acks; /* Number of ACKs in packet */
692 u16 nr_new_acks; /* Number of new ACKs in packet */
693 u16 nr_rot_new_acks; /* Number of rotated new ACKs */
690 u8 ack_reason;694 u8 ack_reason;
691 u8 nr_acks; /* Number of ACKs in packet */
692 u8 nr_new_acks; /* Number of new ACKs in packet */
693 u8 nr_rot_new_acks; /* Number of rotated new ACKs */
694 bool saw_nacks; /* Saw NACKs in packet */695 bool saw_nacks; /* Saw NACKs in packet */
695 bool new_low_nack; /* T if new low NACK found */696 bool new_low_nack; /* T if new low NACK found */
696 bool retrans_timeo; /* T if reTx due to timeout happened */697 bool retrans_timeo; /* T if reTx due to timeout happened */
net/rxrpc/call_accept.c+2−1
@@ -324,7 +324,8 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, · 323 unmodified lines
324 call->security = conn->security;324 call->security = conn->security;
325 call->security_ix = conn->security_ix;325 call->security_ix = conn->security_ix;
326 call->peer = rxrpc_get_peer(conn->params.peer);326 call->peer = rxrpc_get_peer(conn->params.peer);
327 call->cong_cwnd = call->peer->cong_cwnd;327 call->cong_ssthresh = call->peer->cong_ssthresh;
328 call->tx_last_sent = ktime_get_real();
328 return call;329 return call;
329}330}
330 331
net/rxrpc/call_object.c+6−1
@@ -166,7 +166,12 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, · 165 unmodified lines
166 call->rx_winsize = rxrpc_rx_window_size;166 call->rx_winsize = rxrpc_rx_window_size;
167 call->tx_winsize = 16;167 call->tx_winsize = 16;
168 168
169 call->cong_cwnd = 2;169 if (RXRPC_TX_SMSS > 2190)
170 call->cong_cwnd = 2;
171 else if (RXRPC_TX_SMSS > 1095)
172 call->cong_cwnd = 3;
173 else
174 call->cong_cwnd = 4;
170 call->cong_ssthresh = RXRPC_TX_MAX_WINDOW;175 call->cong_ssthresh = RXRPC_TX_MAX_WINDOW;
171 176
172 call->rxnet = rxnet;177 call->rxnet = rxnet;
net/rxrpc/conn_client.c+2−1
@@ -363,7 +363,8 @@ static struct rxrpc_bundle *rxrpc_prep_call(struct rxrpc_sock *rx, · 362 unmodified lines
363 if (!cp->peer)363 if (!cp->peer)
364 goto error;364 goto error;
365 365
366 call->cong_cwnd = cp->peer->cong_cwnd;366 call->tx_last_sent = ktime_get_real();
367 call->cong_ssthresh = cp->peer->cong_ssthresh;
367 if (call->cong_cwnd >= call->cong_ssthresh)368 if (call->cong_cwnd >= call->cong_ssthresh)
368 call->cong_mode = RXRPC_CALL_CONGEST_AVOIDANCE;369 call->cong_mode = RXRPC_CALL_CONGEST_AVOIDANCE;
369 else370 else
net/rxrpc/conn_object.c+1−1
@@ -207,7 +207,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) · 206 unmodified lines
207{207{
208 struct rxrpc_connection *conn = call->conn;208 struct rxrpc_connection *conn = call->conn;
209 209
210 call->peer->cong_cwnd = call->cong_cwnd;210 call->peer->cong_ssthresh = call->cong_ssthresh;
211 211
212 if (!hlist_unhashed(&call->error_link)) {212 if (!hlist_unhashed(&call->error_link)) {
213 spin_lock_bh(&call->peer->lock);213 spin_lock_bh(&call->peer->lock);
net/rxrpc/input.c+20−1
@@ -58,6 +58,25 @@ static void rxrpc_congestion_management(struct rxrpc_call *call, · 57 unmodified lines
58 summary->cumulative_acks = cumulative_acks;58 summary->cumulative_acks = cumulative_acks;
59 summary->dup_acks = call->cong_dup_acks;59 summary->dup_acks = call->cong_dup_acks;
60 60
61 /* If we haven't transmitted anything for >1RTT, we should reset the
62 * congestion management state.
63 */
64 if ((call->cong_mode == RXRPC_CALL_SLOW_START ||
65 call->cong_mode == RXRPC_CALL_CONGEST_AVOIDANCE) &&
66 ktime_before(ktime_add_us(call->tx_last_sent,
67 call->peer->srtt_us >> 3),
68 ktime_get_real())
69 ) {
70 change = rxrpc_cong_idle_reset;
71 summary->mode = RXRPC_CALL_SLOW_START;
72 if (RXRPC_TX_SMSS > 2190)
73 summary->cwnd = 2;
74 else if (RXRPC_TX_SMSS > 1095)
75 summary->cwnd = 3;
76 else
77 summary->cwnd = 4;
78 }
79
61 switch (call->cong_mode) {80 switch (call->cong_mode) {
62 case RXRPC_CALL_SLOW_START:81 case RXRPC_CALL_SLOW_START:
63 if (summary->saw_nacks)82 if (summary->saw_nacks)
@@ -205,7 +224,7 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to, · 141 unmodified lines
205 224
206 if (call->acks_lowest_nak == call->acks_hard_ack) {225 if (call->acks_lowest_nak == call->acks_hard_ack) {
207 call->acks_lowest_nak = to;226 call->acks_lowest_nak = to;
208 } else if (before_eq(call->acks_lowest_nak, to)) {227 } else if (after(to, call->acks_lowest_nak)) {
209 summary->new_low_nack = true;228 summary->new_low_nack = true;
210 call->acks_lowest_nak = to;229 call->acks_lowest_nak = to;
211 }230 }
net/rxrpc/output.c+1−0
@@ -501,6 +501,7 @@ dont_set_request_ack: · 500 unmodified lines
501 501
502done:502done:
503 if (ret >= 0) {503 if (ret >= 0) {
504 call->tx_last_sent = txb->last_sent;
504 if (txb->wire.flags & RXRPC_REQUEST_ACK) {505 if (txb->wire.flags & RXRPC_REQUEST_ACK) {
505 call->peer->rtt_last_req = txb->last_sent;506 call->peer->rtt_last_req = txb->last_sent;
506 if (call->peer->rtt_count > 1) {507 if (call->peer->rtt_count > 1) {
net/rxrpc/peer_object.c+1−6
@@ -227,12 +227,7 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp) · 226 unmodified lines
227 227
228 rxrpc_peer_init_rtt(peer);228 rxrpc_peer_init_rtt(peer);
229 229
230 if (RXRPC_TX_SMSS > 2190)230 peer->cong_ssthresh = RXRPC_TX_MAX_WINDOW;
231 peer->cong_cwnd = 2;
232 else if (RXRPC_TX_SMSS > 1095)
233 peer->cong_cwnd = 3;
234 else
235 peer->cong_cwnd = 4;
236 trace_rxrpc_peer(peer->debug_id, rxrpc_peer_new, 1, here);231 trace_rxrpc_peer(peer->debug_id, rxrpc_peer_new, 1, here);
237 }232 }
238 233
net/rxrpc/proc.c+2−2
@@ -217,7 +217,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v) · 216 unmodified lines
217 seq_puts(seq,217 seq_puts(seq,
218 "Proto Local "218 "Proto Local "
219 " Remote "219 " Remote "
220 " Use CW MTU LastUse RTT RTO\n"220 " Use SST MTU LastUse RTT RTO\n"
221 );221 );
222 return 0;222 return 0;
223 }223 }
@@ -235,7 +235,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v) · 11 unmodified lines
235 lbuff,235 lbuff,
236 rbuff,236 rbuff,
237 refcount_read(&peer->ref),237 refcount_read(&peer->ref),
238 peer->cong_cwnd,238 peer->cong_ssthresh,
239 peer->mtu,239 peer->mtu,
240 now - peer->last_tx_at,240 now - peer->last_tx_at,
241 peer->srtt_us >> 3,241 peer->srtt_us >> 3,
net/rxrpc/sendmsg.c+19−3
@@ -22,11 +22,27 @@ · 21 unmodified lines
22 */22 */
23static bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win)23static bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win)
24{24{
25 unsigned int win_size =25 unsigned int win_size;
26 min_t(unsigned int, call->tx_winsize,
27 call->cong_cwnd + call->cong_extra);
28 rxrpc_seq_t tx_win = smp_load_acquire(&call->acks_hard_ack);26 rxrpc_seq_t tx_win = smp_load_acquire(&call->acks_hard_ack);
29 27
28 /* If we haven't transmitted anything for >1RTT, we should reset the
29 * congestion management state.
30 */
31 if (ktime_before(ktime_add_us(call->tx_last_sent,
32 call->peer->srtt_us >> 3),
33 ktime_get_real())) {
34 if (RXRPC_TX_SMSS > 2190)
35 win_size = 2;
36 else if (RXRPC_TX_SMSS > 1095)
37 win_size = 3;
38 else
39 win_size = 4;
40 win_size += call->cong_extra;
41 } else {
42 win_size = min_t(unsigned int, call->tx_winsize,
43 call->cong_cwnd + call->cong_extra);
44 }
45
30 if (_tx_win)46 if (_tx_win)
31 *_tx_win = tx_win;47 *_tx_win = tx_win;
32 return call->tx_top - tx_win < win_size;48 return call->tx_top - tx_win < win_size;