kcm: Add receive message timeout
This patch adds receive timeout for message assembly on the attached TCP sockets. The timeout is set when a new messages is started and the whole message has not been received by TCP (not in the receive queue). If the completely message is subsequently received the timer is cancelled, if the timer expires the RX side is aborted. The timeout value is taken from the socket timeout (SO_RCVTIMEO) that is set on a TCP socket (i.e. set by get sockopt before attaching a TCP socket to KCM. Signed-off-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7ced95ef52
commit
29152a34f7
3 changed files with 39 additions and 2 deletions
|
@ -29,6 +29,7 @@ struct kcm_psock_stats {
|
|||
unsigned int rx_mem_fail;
|
||||
unsigned int rx_need_more_hdr;
|
||||
unsigned int rx_msg_too_big;
|
||||
unsigned int rx_msg_timeouts;
|
||||
unsigned int rx_bad_hdr_len;
|
||||
unsigned long long reserved;
|
||||
unsigned long long unreserved;
|
||||
|
@ -130,6 +131,7 @@ struct kcm_psock {
|
|||
struct kcm_sock *rx_kcm;
|
||||
unsigned long long saved_rx_bytes;
|
||||
unsigned long long saved_rx_msgs;
|
||||
struct timer_list rx_msg_timer;
|
||||
unsigned int rx_need_bytes;
|
||||
|
||||
/* Transmit */
|
||||
|
@ -194,6 +196,7 @@ static inline void aggregate_psock_stats(struct kcm_psock_stats *stats,
|
|||
SAVE_PSOCK_STATS(rx_mem_fail);
|
||||
SAVE_PSOCK_STATS(rx_need_more_hdr);
|
||||
SAVE_PSOCK_STATS(rx_msg_too_big);
|
||||
SAVE_PSOCK_STATS(rx_msg_timeouts);
|
||||
SAVE_PSOCK_STATS(rx_bad_hdr_len);
|
||||
SAVE_PSOCK_STATS(tx_msgs);
|
||||
SAVE_PSOCK_STATS(tx_bytes);
|
||||
|
|
|
@ -331,7 +331,7 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
|
|||
mux_stats.rx_ready_drops);
|
||||
|
||||
seq_printf(seq,
|
||||
"%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
|
||||
"%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
|
||||
"Psock",
|
||||
"RX-Msgs",
|
||||
"RX-Bytes",
|
||||
|
@ -344,10 +344,11 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
|
|||
"RX-NeedMor",
|
||||
"RX-BadLen",
|
||||
"RX-TooBig",
|
||||
"RX-Timeout",
|
||||
"TX-Aborts");
|
||||
|
||||
seq_printf(seq,
|
||||
"%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u\n",
|
||||
"%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
|
||||
"",
|
||||
psock_stats.rx_msgs,
|
||||
psock_stats.rx_bytes,
|
||||
|
@ -360,6 +361,7 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
|
|||
psock_stats.rx_need_more_hdr,
|
||||
psock_stats.rx_bad_hdr_len,
|
||||
psock_stats.rx_msg_too_big,
|
||||
psock_stats.rx_msg_timeouts,
|
||||
psock_stats.tx_aborts);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -55,6 +55,8 @@ static void kcm_abort_rx_psock(struct kcm_psock *psock, int err,
|
|||
|
||||
/* Unrecoverable error in receive */
|
||||
|
||||
del_timer(&psock->rx_msg_timer);
|
||||
|
||||
if (psock->rx_stopped)
|
||||
return;
|
||||
|
||||
|
@ -351,6 +353,12 @@ static void unreserve_rx_kcm(struct kcm_psock *psock,
|
|||
spin_unlock_bh(&mux->rx_lock);
|
||||
}
|
||||
|
||||
static void kcm_start_rx_timer(struct kcm_psock *psock)
|
||||
{
|
||||
if (psock->sk->sk_rcvtimeo)
|
||||
mod_timer(&psock->rx_msg_timer, psock->sk->sk_rcvtimeo);
|
||||
}
|
||||
|
||||
/* Macro to invoke filter function. */
|
||||
#define KCM_RUN_FILTER(prog, ctx) \
|
||||
(*prog->bpf_func)(ctx, prog->insnsi)
|
||||
|
@ -500,6 +508,10 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
|
|||
|
||||
if (!len) {
|
||||
/* Need more header to determine length */
|
||||
if (!rxm->accum_len) {
|
||||
/* Start RX timer for new message */
|
||||
kcm_start_rx_timer(psock);
|
||||
}
|
||||
rxm->accum_len += cand_len;
|
||||
eaten += cand_len;
|
||||
KCM_STATS_INCR(psock->stats.rx_need_more_hdr);
|
||||
|
@ -540,6 +552,11 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
|
|||
* but don't consume yet per tcp_read_sock.
|
||||
*/
|
||||
|
||||
if (!rxm->accum_len) {
|
||||
/* Start RX timer for new message */
|
||||
kcm_start_rx_timer(psock);
|
||||
}
|
||||
|
||||
psock->rx_need_bytes = rxm->full_len -
|
||||
rxm->accum_len;
|
||||
rxm->accum_len += cand_len;
|
||||
|
@ -563,6 +580,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
|
|||
eaten += (cand_len - extra);
|
||||
|
||||
/* Hurray, we have a new message! */
|
||||
del_timer(&psock->rx_msg_timer);
|
||||
psock->rx_skb_head = NULL;
|
||||
KCM_STATS_INCR(psock->stats.rx_msgs);
|
||||
|
||||
|
@ -1656,6 +1674,15 @@ static void init_kcm_sock(struct kcm_sock *kcm, struct kcm_mux *mux)
|
|||
spin_unlock_bh(&mux->rx_lock);
|
||||
}
|
||||
|
||||
static void kcm_rx_msg_timeout(unsigned long arg)
|
||||
{
|
||||
struct kcm_psock *psock = (struct kcm_psock *)arg;
|
||||
|
||||
/* Message assembly timed out */
|
||||
KCM_STATS_INCR(psock->stats.rx_msg_timeouts);
|
||||
kcm_abort_rx_psock(psock, ETIMEDOUT, NULL);
|
||||
}
|
||||
|
||||
static int kcm_attach(struct socket *sock, struct socket *csock,
|
||||
struct bpf_prog *prog)
|
||||
{
|
||||
|
@ -1685,6 +1712,10 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
|
|||
psock->mux = mux;
|
||||
psock->sk = csk;
|
||||
psock->bpf_prog = prog;
|
||||
|
||||
setup_timer(&psock->rx_msg_timer, kcm_rx_msg_timeout,
|
||||
(unsigned long)psock);
|
||||
|
||||
INIT_WORK(&psock->rx_work, psock_rx_work);
|
||||
INIT_DELAYED_WORK(&psock->rx_delayed_work, psock_rx_delayed_work);
|
||||
|
||||
|
@ -1796,6 +1827,7 @@ static void kcm_unattach(struct kcm_psock *psock)
|
|||
|
||||
write_unlock_bh(&csk->sk_callback_lock);
|
||||
|
||||
del_timer_sync(&psock->rx_msg_timer);
|
||||
cancel_work_sync(&psock->rx_work);
|
||||
cancel_delayed_work_sync(&psock->rx_delayed_work);
|
||||
|
||||
|
|
Loading…
Reference in a new issue