summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCong Wang <cong.wang@bytedance.com>2022-06-15 19:20:11 +0300
committerDaniel Borkmann <daniel@iogearbox.net>2022-06-20 15:05:52 +0300
commit04919bed948dc22a0032a9da867b7dcb8aece4ca (patch)
tree434852050f126b3f99b6bb2d73df48e4cbc1570c
parent4336487e30c37a2e82a1fed2370d3134cc5b6505 (diff)
downloadlinux-04919bed948dc22a0032a9da867b7dcb8aece4ca.tar.xz
tcp: Introduce tcp_read_skb()
This patch inroduces tcp_read_skb() based on tcp_read_sock(), a preparation for the next patch which actually introduces a new sock ops. TCP is special here, because it has tcp_read_sock() which is mainly used by splice(). tcp_read_sock() supports partial read and arbitrary offset, neither of them is needed for sockmap. Signed-off-by: Cong Wang <cong.wang@bytedance.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: John Fastabend <john.fastabend@gmail.com> Link: https://lore.kernel.org/bpf/20220615162014.89193-2-xiyou.wangcong@gmail.com
-rw-r--r--include/net/tcp.h2
-rw-r--r--net/ipv4/tcp.c47
2 files changed, 49 insertions, 0 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index c21a9b516f1e..7547d90fbb57 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -672,6 +672,8 @@ void tcp_get_info(struct sock *, struct tcp_info *);
/* Read 'sendfile()'-style from a TCP socket */
int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor);
+int tcp_read_skb(struct sock *sk, read_descriptor_t *desc,
+ sk_read_actor_t recv_actor);
void tcp_initialize_rcv_mss(struct sock *sk);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index f7309452bdce..124f384f8695 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1734,6 +1734,53 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
}
EXPORT_SYMBOL(tcp_read_sock);
+int tcp_read_skb(struct sock *sk, read_descriptor_t *desc,
+ sk_read_actor_t recv_actor)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ u32 seq = tp->copied_seq;
+ struct sk_buff *skb;
+ int copied = 0;
+ u32 offset;
+
+ if (sk->sk_state == TCP_LISTEN)
+ return -ENOTCONN;
+
+ while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) {
+ int used;
+
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ used = recv_actor(desc, skb, 0, skb->len);
+ if (used <= 0) {
+ if (!copied)
+ copied = used;
+ break;
+ }
+ seq += used;
+ copied += used;
+
+ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) {
+ consume_skb(skb);
+ ++seq;
+ break;
+ }
+ consume_skb(skb);
+ if (!desc->count)
+ break;
+ WRITE_ONCE(tp->copied_seq, seq);
+ }
+ WRITE_ONCE(tp->copied_seq, seq);
+
+ tcp_rcv_space_adjust(sk);
+
+ /* Clean up data we have read: This will do ACK frames. */
+ if (copied > 0)
+ tcp_cleanup_rbuf(sk, copied);
+
+ return copied;
+}
+EXPORT_SYMBOL(tcp_read_skb);
+
int tcp_peek_len(struct socket *sock)
{
return tcp_inq(sock->sk);