diff --git a/include/net/kcm.h b/include/net/kcm.h index d892956ff552..95c425ca97b6 100644 --- a/include/net/kcm.h +++ b/include/net/kcm.h @@ -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); diff --git a/net/kcm/kcmproc.c b/net/kcm/kcmproc.c index 7638b3555b17..738008726cc6 100644 --- a/net/kcm/kcmproc.c +++ b/net/kcm/kcmproc.c @@ -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; diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 8bc38d3fff9a..40662d73204f 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -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);