mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	rxrpc: Add keepalive for a call
We need to transmit a packet every so often to act as a keepalive for the peer (which has a timeout from the last time it received a packet) and also to prevent any intervening firewalls from closing the route. Do this by resetting a timer every time we transmit a packet. If the timer ever expires, we transmit a PING ACK packet and thereby also elicit a PING RESPONSE ACK from the other side - which prevents our last-rx timeout from expiring. The timer is set to 1/6 of the last-rx timeout so that we can detect the other side going away if it misses 6 replies in a row. This is particularly necessary for servers where the processing of the service function may take a significant amount of time. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
		
							parent
							
								
									bd1fdf8cfd
								
							
						
					
					
						commit
						415f44e432
					
				
					 4 changed files with 40 additions and 0 deletions
				
			
		|  | @ -141,6 +141,7 @@ enum rxrpc_timer_trace { | ||||||
| 	rxrpc_timer_exp_ack, | 	rxrpc_timer_exp_ack, | ||||||
| 	rxrpc_timer_exp_hard, | 	rxrpc_timer_exp_hard, | ||||||
| 	rxrpc_timer_exp_idle, | 	rxrpc_timer_exp_idle, | ||||||
|  | 	rxrpc_timer_exp_keepalive, | ||||||
| 	rxrpc_timer_exp_lost_ack, | 	rxrpc_timer_exp_lost_ack, | ||||||
| 	rxrpc_timer_exp_normal, | 	rxrpc_timer_exp_normal, | ||||||
| 	rxrpc_timer_exp_ping, | 	rxrpc_timer_exp_ping, | ||||||
|  | @ -152,6 +153,7 @@ enum rxrpc_timer_trace { | ||||||
| 	rxrpc_timer_set_for_ack, | 	rxrpc_timer_set_for_ack, | ||||||
| 	rxrpc_timer_set_for_hard, | 	rxrpc_timer_set_for_hard, | ||||||
| 	rxrpc_timer_set_for_idle, | 	rxrpc_timer_set_for_idle, | ||||||
|  | 	rxrpc_timer_set_for_keepalive, | ||||||
| 	rxrpc_timer_set_for_lost_ack, | 	rxrpc_timer_set_for_lost_ack, | ||||||
| 	rxrpc_timer_set_for_normal, | 	rxrpc_timer_set_for_normal, | ||||||
| 	rxrpc_timer_set_for_ping, | 	rxrpc_timer_set_for_ping, | ||||||
|  | @ -162,6 +164,7 @@ enum rxrpc_timer_trace { | ||||||
| enum rxrpc_propose_ack_trace { | enum rxrpc_propose_ack_trace { | ||||||
| 	rxrpc_propose_ack_client_tx_end, | 	rxrpc_propose_ack_client_tx_end, | ||||||
| 	rxrpc_propose_ack_input_data, | 	rxrpc_propose_ack_input_data, | ||||||
|  | 	rxrpc_propose_ack_ping_for_keepalive, | ||||||
| 	rxrpc_propose_ack_ping_for_lost_ack, | 	rxrpc_propose_ack_ping_for_lost_ack, | ||||||
| 	rxrpc_propose_ack_ping_for_lost_reply, | 	rxrpc_propose_ack_ping_for_lost_reply, | ||||||
| 	rxrpc_propose_ack_ping_for_params, | 	rxrpc_propose_ack_ping_for_params, | ||||||
|  | @ -311,6 +314,7 @@ enum rxrpc_congest_change { | ||||||
| 	EM(rxrpc_timer_exp_ack,			"ExpAck") \ | 	EM(rxrpc_timer_exp_ack,			"ExpAck") \ | ||||||
| 	EM(rxrpc_timer_exp_hard,		"ExpHrd") \ | 	EM(rxrpc_timer_exp_hard,		"ExpHrd") \ | ||||||
| 	EM(rxrpc_timer_exp_idle,		"ExpIdl") \ | 	EM(rxrpc_timer_exp_idle,		"ExpIdl") \ | ||||||
|  | 	EM(rxrpc_timer_exp_keepalive,		"ExpKA ") \ | ||||||
| 	EM(rxrpc_timer_exp_lost_ack,		"ExpLoA") \ | 	EM(rxrpc_timer_exp_lost_ack,		"ExpLoA") \ | ||||||
| 	EM(rxrpc_timer_exp_normal,		"ExpNml") \ | 	EM(rxrpc_timer_exp_normal,		"ExpNml") \ | ||||||
| 	EM(rxrpc_timer_exp_ping,		"ExpPng") \ | 	EM(rxrpc_timer_exp_ping,		"ExpPng") \ | ||||||
|  | @ -321,6 +325,7 @@ enum rxrpc_congest_change { | ||||||
| 	EM(rxrpc_timer_set_for_ack,		"SetAck") \ | 	EM(rxrpc_timer_set_for_ack,		"SetAck") \ | ||||||
| 	EM(rxrpc_timer_set_for_hard,		"SetHrd") \ | 	EM(rxrpc_timer_set_for_hard,		"SetHrd") \ | ||||||
| 	EM(rxrpc_timer_set_for_idle,		"SetIdl") \ | 	EM(rxrpc_timer_set_for_idle,		"SetIdl") \ | ||||||
|  | 	EM(rxrpc_timer_set_for_keepalive,	"KeepAl") \ | ||||||
| 	EM(rxrpc_timer_set_for_lost_ack,	"SetLoA") \ | 	EM(rxrpc_timer_set_for_lost_ack,	"SetLoA") \ | ||||||
| 	EM(rxrpc_timer_set_for_normal,		"SetNml") \ | 	EM(rxrpc_timer_set_for_normal,		"SetNml") \ | ||||||
| 	EM(rxrpc_timer_set_for_ping,		"SetPng") \ | 	EM(rxrpc_timer_set_for_ping,		"SetPng") \ | ||||||
|  | @ -330,6 +335,7 @@ enum rxrpc_congest_change { | ||||||
| #define rxrpc_propose_ack_traces \ | #define rxrpc_propose_ack_traces \ | ||||||
| 	EM(rxrpc_propose_ack_client_tx_end,	"ClTxEnd") \ | 	EM(rxrpc_propose_ack_client_tx_end,	"ClTxEnd") \ | ||||||
| 	EM(rxrpc_propose_ack_input_data,	"DataIn ") \ | 	EM(rxrpc_propose_ack_input_data,	"DataIn ") \ | ||||||
|  | 	EM(rxrpc_propose_ack_ping_for_keepalive, "KeepAlv") \ | ||||||
| 	EM(rxrpc_propose_ack_ping_for_lost_ack,	"LostAck") \ | 	EM(rxrpc_propose_ack_ping_for_lost_ack,	"LostAck") \ | ||||||
| 	EM(rxrpc_propose_ack_ping_for_lost_reply, "LostRpl") \ | 	EM(rxrpc_propose_ack_ping_for_lost_reply, "LostRpl") \ | ||||||
| 	EM(rxrpc_propose_ack_ping_for_params,	"Params ") \ | 	EM(rxrpc_propose_ack_ping_for_params,	"Params ") \ | ||||||
|  |  | ||||||
|  | @ -519,6 +519,7 @@ struct rxrpc_call { | ||||||
| 	unsigned long		ack_lost_at;	/* When ACK is figured as lost */ | 	unsigned long		ack_lost_at;	/* When ACK is figured as lost */ | ||||||
| 	unsigned long		resend_at;	/* When next resend needs to happen */ | 	unsigned long		resend_at;	/* When next resend needs to happen */ | ||||||
| 	unsigned long		ping_at;	/* When next to send a ping */ | 	unsigned long		ping_at;	/* When next to send a ping */ | ||||||
|  | 	unsigned long		keepalive_at;	/* When next to send a keepalive ping */ | ||||||
| 	unsigned long		expect_rx_by;	/* When we expect to get a packet by */ | 	unsigned long		expect_rx_by;	/* When we expect to get a packet by */ | ||||||
| 	unsigned long		expect_req_by;	/* When we expect to get a request DATA packet by */ | 	unsigned long		expect_req_by;	/* When we expect to get a request DATA packet by */ | ||||||
| 	unsigned long		expect_term_by;	/* When we expect call termination by */ | 	unsigned long		expect_term_by;	/* When we expect call termination by */ | ||||||
|  |  | ||||||
|  | @ -366,6 +366,15 @@ recheck_state: | ||||||
| 		set_bit(RXRPC_CALL_EV_ACK_LOST, &call->events); | 		set_bit(RXRPC_CALL_EV_ACK_LOST, &call->events); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	t = READ_ONCE(call->keepalive_at); | ||||||
|  | 	if (time_after_eq(now, t)) { | ||||||
|  | 		trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now); | ||||||
|  | 		cmpxchg(&call->keepalive_at, t, now + MAX_JIFFY_OFFSET); | ||||||
|  | 		rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, true, | ||||||
|  | 				  rxrpc_propose_ack_ping_for_keepalive); | ||||||
|  | 		set_bit(RXRPC_CALL_EV_PING, &call->events); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	t = READ_ONCE(call->ping_at); | 	t = READ_ONCE(call->ping_at); | ||||||
| 	if (time_after_eq(now, t)) { | 	if (time_after_eq(now, t)) { | ||||||
| 		trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now); | 		trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now); | ||||||
|  | @ -423,6 +432,7 @@ recheck_state: | ||||||
| 	set(call->ack_at); | 	set(call->ack_at); | ||||||
| 	set(call->ack_lost_at); | 	set(call->ack_lost_at); | ||||||
| 	set(call->resend_at); | 	set(call->resend_at); | ||||||
|  | 	set(call->keepalive_at); | ||||||
| 	set(call->ping_at); | 	set(call->ping_at); | ||||||
| 
 | 
 | ||||||
| 	now = jiffies; | 	now = jiffies; | ||||||
|  |  | ||||||
|  | @ -32,6 +32,24 @@ struct rxrpc_abort_buffer { | ||||||
| 	__be32 abort_code; | 	__be32 abort_code; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  | static void rxrpc_set_keepalive(struct rxrpc_call *call) | ||||||
|  | { | ||||||
|  | 	unsigned long now = jiffies, keepalive_at = call->next_rx_timo / 6; | ||||||
|  | 
 | ||||||
|  | 	keepalive_at += now; | ||||||
|  | 	WRITE_ONCE(call->keepalive_at, keepalive_at); | ||||||
|  | 	rxrpc_reduce_call_timer(call, keepalive_at, now, | ||||||
|  | 				rxrpc_timer_set_for_keepalive); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Fill out an ACK packet. |  * Fill out an ACK packet. | ||||||
|  */ |  */ | ||||||
|  | @ -205,6 +223,8 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping, | ||||||
| 				call->ackr_seen = top; | 				call->ackr_seen = top; | ||||||
| 			spin_unlock_bh(&call->lock); | 			spin_unlock_bh(&call->lock); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		rxrpc_set_keepalive(call); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
|  | @ -388,6 +408,9 @@ done: | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	rxrpc_set_keepalive(call); | ||||||
|  | 
 | ||||||
| 	_leave(" = %d [%u]", ret, call->peer->maxdata); | 	_leave(" = %d [%u]", ret, call->peer->maxdata); | ||||||
| 	return ret; | 	return ret; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 David Howells
						David Howells