aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Herbert <tom@herbertland.com>2016-03-07 17:11:10 -0500
committerDavid S. Miller <davem@davemloft.net>2016-03-09 16:36:15 -0500
commit7ced95ef525c329f947c424859cf2b0a3b731f8c (patch)
treebdbbbc12cf0b1b82f4c07b36d1c45262c2dd3af3
parentf29698fc6b3a45a5c6147eca8379f38be8232117 (diff)
kcm: Add memory limit for receive message construction
Message assembly is performed on the TCP socket. This is logically equivalent of an application that performs a peek on the socket to find out how much memory is needed for a receive buffer. The receive socket buffer also provides the maximum message size which is checked. The receive algorithm is something like: 1) Receive the first skbuf for a message (or skbufs if multiple are needed to determine message length). 2) Check the message length against the number of bytes in the TCP receive queue (tcp_inq()). - If all the bytes of the message are in the queue (incluing the skbuf received), then proceed with message assembly (it should complete with the tcp_read_sock) - Else, mark the psock with the number of bytes needed to complete the message. 3) In TCP data ready function, if the psock indicates that we are waiting for the rest of the bytes of a messages, check the number of queued bytes against that. - If there are still not enough bytes for the message, just return - Else, clear the waiting bytes and proceed to receive the skbufs. The message should now be received in one tcp_read_sock Signed-off-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/kcm.h4
-rw-r--r--net/kcm/kcmproc.c6
-rw-r--r--net/kcm/kcmsock.c44
3 files changed, 52 insertions, 2 deletions
diff --git a/include/net/kcm.h b/include/net/kcm.h
index 39c7abe98552..d892956ff552 100644
--- a/include/net/kcm.h
+++ b/include/net/kcm.h
@@ -28,6 +28,7 @@ struct kcm_psock_stats {
28 unsigned int rx_aborts; 28 unsigned int rx_aborts;
29 unsigned int rx_mem_fail; 29 unsigned int rx_mem_fail;
30 unsigned int rx_need_more_hdr; 30 unsigned int rx_need_more_hdr;
31 unsigned int rx_msg_too_big;
31 unsigned int rx_bad_hdr_len; 32 unsigned int rx_bad_hdr_len;
32 unsigned long long reserved; 33 unsigned long long reserved;
33 unsigned long long unreserved; 34 unsigned long long unreserved;
@@ -66,6 +67,7 @@ struct kcm_rx_msg {
66 int full_len; 67 int full_len;
67 int accum_len; 68 int accum_len;
68 int offset; 69 int offset;
70 int early_eaten;
69}; 71};
70 72
71/* Socket structure for KCM client sockets */ 73/* Socket structure for KCM client sockets */
@@ -128,6 +130,7 @@ struct kcm_psock {
128 struct kcm_sock *rx_kcm; 130 struct kcm_sock *rx_kcm;
129 unsigned long long saved_rx_bytes; 131 unsigned long long saved_rx_bytes;
130 unsigned long long saved_rx_msgs; 132 unsigned long long saved_rx_msgs;
133 unsigned int rx_need_bytes;
131 134
132 /* Transmit */ 135 /* Transmit */
133 struct kcm_sock *tx_kcm; 136 struct kcm_sock *tx_kcm;
@@ -190,6 +193,7 @@ static inline void aggregate_psock_stats(struct kcm_psock_stats *stats,
190 SAVE_PSOCK_STATS(rx_aborts); 193 SAVE_PSOCK_STATS(rx_aborts);
191 SAVE_PSOCK_STATS(rx_mem_fail); 194 SAVE_PSOCK_STATS(rx_mem_fail);
192 SAVE_PSOCK_STATS(rx_need_more_hdr); 195 SAVE_PSOCK_STATS(rx_need_more_hdr);
196 SAVE_PSOCK_STATS(rx_msg_too_big);
193 SAVE_PSOCK_STATS(rx_bad_hdr_len); 197 SAVE_PSOCK_STATS(rx_bad_hdr_len);
194 SAVE_PSOCK_STATS(tx_msgs); 198 SAVE_PSOCK_STATS(tx_msgs);
195 SAVE_PSOCK_STATS(tx_bytes); 199 SAVE_PSOCK_STATS(tx_bytes);
diff --git a/net/kcm/kcmproc.c b/net/kcm/kcmproc.c
index 5eb9809c0f59..7638b3555b17 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)
331 mux_stats.rx_ready_drops); 331 mux_stats.rx_ready_drops);
332 332
333 seq_printf(seq, 333 seq_printf(seq,
334 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", 334 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
335 "Psock", 335 "Psock",
336 "RX-Msgs", 336 "RX-Msgs",
337 "RX-Bytes", 337 "RX-Bytes",
@@ -343,10 +343,11 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
343 "RX-MemFail", 343 "RX-MemFail",
344 "RX-NeedMor", 344 "RX-NeedMor",
345 "RX-BadLen", 345 "RX-BadLen",
346 "RX-TooBig",
346 "TX-Aborts"); 347 "TX-Aborts");
347 348
348 seq_printf(seq, 349 seq_printf(seq,
349 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u\n", 350 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u\n",
350 "", 351 "",
351 psock_stats.rx_msgs, 352 psock_stats.rx_msgs,
352 psock_stats.rx_bytes, 353 psock_stats.rx_bytes,
@@ -358,6 +359,7 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
358 psock_stats.rx_mem_fail, 359 psock_stats.rx_mem_fail,
359 psock_stats.rx_need_more_hdr, 360 psock_stats.rx_need_more_hdr,
360 psock_stats.rx_bad_hdr_len, 361 psock_stats.rx_bad_hdr_len,
362 psock_stats.rx_msg_too_big,
361 psock_stats.tx_aborts); 363 psock_stats.tx_aborts);
362 364
363 return 0; 365 return 0;
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index 9ac24995691c..8bc38d3fff9a 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -375,6 +375,19 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
375 if (head) { 375 if (head) {
376 /* Message already in progress */ 376 /* Message already in progress */
377 377
378 rxm = kcm_rx_msg(head);
379 if (unlikely(rxm->early_eaten)) {
380 /* Already some number of bytes on the receive sock
381 * data saved in rx_skb_head, just indicate they
382 * are consumed.
383 */
384 eaten = orig_len <= rxm->early_eaten ?
385 orig_len : rxm->early_eaten;
386 rxm->early_eaten -= eaten;
387
388 return eaten;
389 }
390
378 if (unlikely(orig_offset)) { 391 if (unlikely(orig_offset)) {
379 /* Getting data with a non-zero offset when a message is 392 /* Getting data with a non-zero offset when a message is
380 * in progress is not expected. If it does happen, we 393 * in progress is not expected. If it does happen, we
@@ -492,6 +505,13 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
492 KCM_STATS_INCR(psock->stats.rx_need_more_hdr); 505 KCM_STATS_INCR(psock->stats.rx_need_more_hdr);
493 WARN_ON(eaten != orig_len); 506 WARN_ON(eaten != orig_len);
494 break; 507 break;
508 } else if (len > psock->sk->sk_rcvbuf) {
509 /* Message length exceeds maximum allowed */
510 KCM_STATS_INCR(psock->stats.rx_msg_too_big);
511 desc->error = -EMSGSIZE;
512 psock->rx_skb_head = NULL;
513 kcm_abort_rx_psock(psock, EMSGSIZE, head);
514 break;
495 } else if (len <= (ssize_t)head->len - 515 } else if (len <= (ssize_t)head->len -
496 skb->len - rxm->offset) { 516 skb->len - rxm->offset) {
497 /* Length must be into new skb (and also 517 /* Length must be into new skb (and also
@@ -511,6 +531,23 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
511 531
512 if (extra < 0) { 532 if (extra < 0) {
513 /* Message not complete yet. */ 533 /* Message not complete yet. */
534 if (rxm->full_len - rxm->accum_len >
535 tcp_inq(psock->sk)) {
536 /* Don't have the whole messages in the socket
537 * buffer. Set psock->rx_need_bytes to wait for
538 * the rest of the message. Also, set "early
539 * eaten" since we've already buffered the skb
540 * but don't consume yet per tcp_read_sock.
541 */
542
543 psock->rx_need_bytes = rxm->full_len -
544 rxm->accum_len;
545 rxm->accum_len += cand_len;
546 rxm->early_eaten = cand_len;
547 KCM_STATS_ADD(psock->stats.rx_bytes, cand_len);
548 desc->count = 0; /* Stop reading socket */
549 break;
550 }
514 rxm->accum_len += cand_len; 551 rxm->accum_len += cand_len;
515 eaten += cand_len; 552 eaten += cand_len;
516 WARN_ON(eaten != orig_len); 553 WARN_ON(eaten != orig_len);
@@ -582,6 +619,13 @@ static void psock_tcp_data_ready(struct sock *sk)
582 if (psock->ready_rx_msg) 619 if (psock->ready_rx_msg)
583 goto out; 620 goto out;
584 621
622 if (psock->rx_need_bytes) {
623 if (tcp_inq(sk) >= psock->rx_need_bytes)
624 psock->rx_need_bytes = 0;
625 else
626 goto out;
627 }
628
585 if (psock_tcp_read_sock(psock) == -ENOMEM) 629 if (psock_tcp_read_sock(psock) == -ENOMEM)
586 queue_delayed_work(kcm_wq, &psock->rx_delayed_work, 0); 630 queue_delayed_work(kcm_wq, &psock->rx_delayed_work, 0);
587 631