Skip to content

Commit df890ce

Browse files
author
Paolo Abeni
committed
Merge branch 'fix-poll-behaviour-for-tcp-based-tunnel-protocols'
Ralf Lici says: ==================== fix poll behaviour for TCP-based tunnel protocols This patch series introduces a polling function for datagram-style sockets that operates on custom skb queues, and updates ovpn (the OpenVPN data-channel offload module) and espintcp (the TCP Encapsulation of IKE and IPsec Packets implementation) to use it accordingly. Protocols like the aforementioned one decapsulate packets received over TCP and deliver userspace-bound data through a separate skb queue, not the standard sk_receive_queue. Previously, both relied on datagram_poll(), which would signal readiness based on non-userspace packets, leading to misleading poll results and unnecessary recv attempts in userspace. Patch 1 introduces datagram_poll_queue(), a variant of datagram_poll() that accepts an explicit receive queue. This builds on the approach introduced in commit b50b058, which extended other skb-related functions to support custom queues. Patch 2 and 3 update espintcp_poll() and ovpn_tcp_poll() respectively to use this helper, ensuring readiness is only signaled when userspace data is available. Each patch is self-contained and the ovpn one includes rationale and lifecycle enforcement where appropriate. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 10843e1 + efd7294 commit df890ce

File tree

4 files changed

+60
-19
lines changed

4 files changed

+60
-19
lines changed

drivers/net/ovpn/tcp.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -560,16 +560,34 @@ static void ovpn_tcp_close(struct sock *sk, long timeout)
560560
static __poll_t ovpn_tcp_poll(struct file *file, struct socket *sock,
561561
poll_table *wait)
562562
{
563-
__poll_t mask = datagram_poll(file, sock, wait);
563+
struct sk_buff_head *queue = &sock->sk->sk_receive_queue;
564564
struct ovpn_socket *ovpn_sock;
565+
struct ovpn_peer *peer = NULL;
566+
__poll_t mask;
565567

566568
rcu_read_lock();
567569
ovpn_sock = rcu_dereference_sk_user_data(sock->sk);
568-
if (ovpn_sock && ovpn_sock->peer &&
569-
!skb_queue_empty(&ovpn_sock->peer->tcp.user_queue))
570-
mask |= EPOLLIN | EPOLLRDNORM;
570+
/* if we landed in this callback, we expect to have a
571+
* meaningful state. The ovpn_socket lifecycle would
572+
* prevent it otherwise.
573+
*/
574+
if (WARN(!ovpn_sock || !ovpn_sock->peer,
575+
"ovpn: null state in ovpn_tcp_poll!")) {
576+
rcu_read_unlock();
577+
return 0;
578+
}
579+
580+
if (ovpn_peer_hold(ovpn_sock->peer)) {
581+
peer = ovpn_sock->peer;
582+
queue = &peer->tcp.user_queue;
583+
}
571584
rcu_read_unlock();
572585

586+
mask = datagram_poll_queue(file, sock, wait, queue);
587+
588+
if (peer)
589+
ovpn_peer_put(peer);
590+
573591
return mask;
574592
}
575593

include/linux/skbuff.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4204,6 +4204,9 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk,
42044204
struct sk_buff_head *sk_queue,
42054205
unsigned int flags, int *off, int *err);
42064206
struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned int flags, int *err);
4207+
__poll_t datagram_poll_queue(struct file *file, struct socket *sock,
4208+
struct poll_table_struct *wait,
4209+
struct sk_buff_head *rcv_queue);
42074210
__poll_t datagram_poll(struct file *file, struct socket *sock,
42084211
struct poll_table_struct *wait);
42094212
int skb_copy_datagram_iter(const struct sk_buff *from, int offset,

net/core/datagram.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -920,21 +920,22 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
920920
EXPORT_SYMBOL(skb_copy_and_csum_datagram_msg);
921921

922922
/**
923-
* datagram_poll - generic datagram poll
923+
* datagram_poll_queue - same as datagram_poll, but on a specific receive
924+
* queue
924925
* @file: file struct
925926
* @sock: socket
926927
* @wait: poll table
928+
* @rcv_queue: receive queue to poll
927929
*
928-
* Datagram poll: Again totally generic. This also handles
929-
* sequenced packet sockets providing the socket receive queue
930-
* is only ever holding data ready to receive.
930+
* Performs polling on the given receive queue, handling shutdown, error,
931+
* and connection state. This is useful for protocols that deliver
932+
* userspace-bound packets through a custom queue instead of
933+
* sk->sk_receive_queue.
931934
*
932-
* Note: when you *don't* use this routine for this protocol,
933-
* and you use a different write policy from sock_writeable()
934-
* then please supply your own write_space callback.
935+
* Return: poll bitmask indicating the socket's current state
935936
*/
936-
__poll_t datagram_poll(struct file *file, struct socket *sock,
937-
poll_table *wait)
937+
__poll_t datagram_poll_queue(struct file *file, struct socket *sock,
938+
poll_table *wait, struct sk_buff_head *rcv_queue)
938939
{
939940
struct sock *sk = sock->sk;
940941
__poll_t mask;
@@ -956,7 +957,7 @@ __poll_t datagram_poll(struct file *file, struct socket *sock,
956957
mask |= EPOLLHUP;
957958

958959
/* readable? */
959-
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
960+
if (!skb_queue_empty_lockless(rcv_queue))
960961
mask |= EPOLLIN | EPOLLRDNORM;
961962

962963
/* Connection-based need to check for termination and startup */
@@ -978,4 +979,27 @@ __poll_t datagram_poll(struct file *file, struct socket *sock,
978979

979980
return mask;
980981
}
982+
EXPORT_SYMBOL(datagram_poll_queue);
983+
984+
/**
985+
* datagram_poll - generic datagram poll
986+
* @file: file struct
987+
* @sock: socket
988+
* @wait: poll table
989+
*
990+
* Datagram poll: Again totally generic. This also handles
991+
* sequenced packet sockets providing the socket receive queue
992+
* is only ever holding data ready to receive.
993+
*
994+
* Note: when you *don't* use this routine for this protocol,
995+
* and you use a different write policy from sock_writeable()
996+
* then please supply your own write_space callback.
997+
*
998+
* Return: poll bitmask indicating the socket's current state
999+
*/
1000+
__poll_t datagram_poll(struct file *file, struct socket *sock, poll_table *wait)
1001+
{
1002+
return datagram_poll_queue(file, sock, wait,
1003+
&sock->sk->sk_receive_queue);
1004+
}
9811005
EXPORT_SYMBOL(datagram_poll);

net/xfrm/espintcp.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -555,14 +555,10 @@ static void espintcp_close(struct sock *sk, long timeout)
555555
static __poll_t espintcp_poll(struct file *file, struct socket *sock,
556556
poll_table *wait)
557557
{
558-
__poll_t mask = datagram_poll(file, sock, wait);
559558
struct sock *sk = sock->sk;
560559
struct espintcp_ctx *ctx = espintcp_getctx(sk);
561560

562-
if (!skb_queue_empty(&ctx->ike_queue))
563-
mask |= EPOLLIN | EPOLLRDNORM;
564-
565-
return mask;
561+
return datagram_poll_queue(file, sock, wait, &ctx->ike_queue);
566562
}
567563

568564
static void build_protos(struct proto *espintcp_prot,

0 commit comments

Comments
 (0)