mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Bobby Eshleman <bobbyeshleman@meta.com>
To: Sergio Lopez <slp@redhat.com>
Cc: "Stefano Garzarella" <sgarzare@redhat.com>,
	"David S. Miller" <davem@davemloft.net>,
	"Eric Dumazet" <edumazet@kernel.org>,
	"Jakub Kicinski" <kuba@kernel.org>,
	"Paolo Abeni" <pabeni@redhat.com>,
	"Simon Horman" <horms@kernel.org>,
	"Bryan Tan" <bryan-bt.tan@broadcom.com>,
	"Vishnu Dasa" <vishnu.dasa@broadcom.com>,
	"Broadcom internal kernel review list"
	<bcm-kernel-feedback-list@broadcom.com>,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Jason Wang" <jasowangio@gmail.com>,
	"Eugenio Pérez" <eperezma@redhat.com>,
	"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
	"Haiyang Zhang" <haiyangz@microsoft.com>,
	"Wei Liu" <wei.liu@kernel.org>,
	"Dexuan Cui" <decui@microsoft.com>,
	virtualization@lists.linux.dev, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, kvm@vger.kernel.org,
	bpf@vger.kernel.org, linux-hyperv@vger.kernel.org
Subject: Re: [PATCH RFC 3/8] vsock/virtio: implement the datagram data path
Date: Tue, 3 Nov 2026 12:05:49 -0800	[thread overview]
Message-ID: <auo+nf3+0Mdm8vpi@devvm29614.prn0.facebook.com> (raw)
In-Reply-To: <20261028-vsock-dgram-support-v1-3-e457cf7cee78@sinrega.org>

On Wed, Oct 28, 2026 at 05:04:32PM +0100, Sergio Lopez wrote:
> Add the datagram feature bit and packet type, and implement the common
> virtio transport operations needed to bind, send, and receive
> datagrams.
> 
> Send each message as an OP_RW packet with a maximum 64 KiB payload,
> including support for empty messages. Bound pending sends by the
> socket send buffer instead of connection-oriented peer credits. Charge
> pending payload bytes before handing the skb to the backend and
> release that charge exactly once on completion, rejection, or queued
> drops.
> 
> Deliver incoming datagrams through the bound table without entering
> the connection state machine. Validate the transport and connected
> peer under the socket lock, including after shutdown, and silently
> discard undeliverable messages. Use the socket datagram queue for
> recvmsg(), including source addresses, peeking, and truncation
> reporting based on the payload length after socket filtering.  Reject
> MSG_OOB and MSG_ERRQUEUE before accessing the receive queue.  Reject
> datagram sockmap admission until its receive callbacks support it.
> 
> Signed-off-by: Sergio Lopez <slp@redhat.com>
> ---
>  include/linux/virtio_vsock.h            |   2 +
>  include/uapi/linux/virtio_vsock.h       |   2 +
>  net/vmw_vsock/virtio_transport_common.c | 150 +++++++++++++++++++++++++++++---
>  net/vmw_vsock/vsock_bpf.c               |   3 +-
>  4 files changed, 142 insertions(+), 15 deletions(-)
> 
> diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
> index f91704731057..0bccae661221 100644
> --- a/include/linux/virtio_vsock.h
> +++ b/include/linux/virtio_vsock.h
> @@ -12,6 +12,8 @@
>  struct virtio_vsock_skb_cb {
>  	bool reply;
>  	bool tap_delivered;
> +	/* Datagram payload is still charged to bytes_unsent. */
> +	bool tx_accounted;
>  	u32 offset;
>  };
>  
> diff --git a/include/uapi/linux/virtio_vsock.h b/include/uapi/linux/virtio_vsock.h
> index 64738838bee5..27b4b2b8bf13 100644
> --- a/include/uapi/linux/virtio_vsock.h
> +++ b/include/uapi/linux/virtio_vsock.h
> @@ -40,6 +40,7 @@
>  
>  /* The feature bitmap for virtio vsock */
>  #define VIRTIO_VSOCK_F_SEQPACKET	1	/* SOCK_SEQPACKET supported */
> +#define VIRTIO_VSOCK_F_DGRAM		3	/* SOCK_DGRAM supported */
>  
>  struct virtio_vsock_config {
>  	__le64 guest_cid;
> @@ -69,6 +70,7 @@ struct virtio_vsock_hdr {
>  enum virtio_vsock_type {
>  	VIRTIO_VSOCK_TYPE_STREAM = 1,
>  	VIRTIO_VSOCK_TYPE_SEQPACKET = 2,
> +	VIRTIO_VSOCK_TYPE_DGRAM = 3,
>  };
>  
>  enum virtio_vsock_op {
> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> index 1e762a480df4..ae33630d99e7 100644
> --- a/net/vmw_vsock/virtio_transport_common.c
> +++ b/net/vmw_vsock/virtio_transport_common.c
> @@ -204,10 +204,18 @@ static u16 virtio_transport_get_type(struct sock *sk)
>  {
>  	if (sk->sk_type == SOCK_STREAM)
>  		return VIRTIO_VSOCK_TYPE_STREAM;
> +	else if (sk->sk_type == SOCK_DGRAM)
> +		return VIRTIO_VSOCK_TYPE_DGRAM;
>  	else
>  		return VIRTIO_VSOCK_TYPE_SEQPACKET;
>  }
>  
> +static void virtio_transport_dgram_skb_destructor(struct sk_buff *skb)
> +{
> +	virtio_transport_consume_skb_sent(skb, false);
> +	sock_wfree(skb);
> +}
> +
>  /* Returns new sk_buff on success, otherwise returns NULL. */
>  static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info,
>  						  size_t payload_len,
> @@ -303,6 +311,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
>  	u32 src_cid, src_port, dst_cid, dst_port;
>  	const struct virtio_transport *t_ops;
>  	struct iov_iter_state msg_iter_state;
> +	struct sock *sk = sk_vsock(vsk);
>  	struct virtio_vsock_sock *vvs;
>  	struct ubuf_info *uarg = NULL;
>  	u32 pkt_len = info->pkt_len;
> @@ -329,12 +338,24 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
>  
>  	vvs = vsk->trans;
>  
> -	/* virtio_transport_get_credit might return less than pkt_len credit */
> -	pkt_len = virtio_transport_get_credit(vvs, pkt_len);
> +	if (info->type == VIRTIO_VSOCK_TYPE_DGRAM) {
> +		if (pkt_len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE)
> +			return -EMSGSIZE;
>  
> -	/* Do not send zero length OP_RW pkt */
> -	if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW)
> -		return pkt_len;
> +		/* Datagram sends are serialized by the socket lock. */
> +		if (sk_wmem_alloc_get(sk) >= READ_ONCE(sk->sk_sndbuf)) {
> +			sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
> +			set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
> +			return -EAGAIN;
> +		}
> +	} else {
> +		/* virtio_transport_get_credit might return less than pkt_len credit */
> +		pkt_len = virtio_transport_get_credit(vvs, pkt_len);
> +
> +		/* Do not send zero length OP_RW pkt */
> +		if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW)
> +			return pkt_len;
> +	}
>  
>  	if (info->msg && (info->msg->msg_flags & MSG_ZEROCOPY)) {
>  		/* If 'info->msg' is not NULL, this is only VIRTIO_VSOCK_OP_RW.
> @@ -348,7 +369,8 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
>  			uarg = msg_zerocopy_realloc(sk_vsock(vsk), pkt_len,
>  						    NULL, false);
>  			if (!uarg) {
> -				virtio_transport_put_credit(vvs, pkt_len);
> +				if (info->type != VIRTIO_VSOCK_TYPE_DGRAM)
> +					virtio_transport_put_credit(vvs, pkt_len);
>  				return -ENOMEM;
>  			}
>  
> @@ -393,7 +415,15 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
>  			break;
>  		}
>  
> -		virtio_transport_inc_tx_pkt(vvs, skb);
> +		if (info->type == VIRTIO_VSOCK_TYPE_DGRAM) {
> +			spin_lock_bh(&vvs->tx_lock);
> +			vvs->bytes_unsent += skb_len;
> +			spin_unlock_bh(&vvs->tx_lock);
> +			VIRTIO_VSOCK_SKB_CB(skb)->tx_accounted = true;
> +			skb->destructor = virtio_transport_dgram_skb_destructor;
> +		} else {
> +			virtio_transport_inc_tx_pkt(vvs, skb);
> +		}
>  
>  		ret = t_ops->send_pkt(skb, info->net);
>  		if (ret < 0)
> @@ -416,7 +446,8 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
>  	if (info->msg && ret < 0)
>  		iov_iter_restore(&info->msg->msg_iter, &msg_iter_state);
>  
> -	virtio_transport_put_credit(vvs, rest_len);
> +	if (info->type != VIRTIO_VSOCK_TYPE_DGRAM)
> +		virtio_transport_put_credit(vvs, rest_len);
>  
>  	/* msg_zerocopy_realloc() initializes the ubuf_info refcnt to 1.
>  	 * skb_zcopy_set() increases it for each skb, so we can drop that
> @@ -620,7 +651,9 @@ void virtio_transport_consume_skb_sent(struct sk_buff *skb, bool consume)
>  {
>  	struct sock *s = skb->sk;
>  
> -	if (s && skb->len) {
> +	if (s && skb->len &&
> +	    (s->sk_type != SOCK_DGRAM ||
> +	     VIRTIO_VSOCK_SKB_CB(skb)->tx_accounted)) {
>  		struct vsock_sock *vs = vsock_sk(s);
>  		struct virtio_vsock_sock *vvs;
>  
> @@ -631,6 +664,9 @@ void virtio_transport_consume_skb_sent(struct sk_buff *skb, bool consume)
>  		spin_unlock_bh(&vvs->tx_lock);
>  	}
>  
> +	if (s && s->sk_type == SOCK_DGRAM)
> +		VIRTIO_VSOCK_SKB_CB(skb)->tx_accounted = false;
> +
>  	if (consume)
>  		consume_skb(skb);
>  }
> @@ -999,7 +1035,47 @@ virtio_transport_dgram_dequeue(struct vsock_sock *vsk,
>  			       struct msghdr *msg,
>  			       size_t len, int flags)
>  {
> -	return -EOPNOTSUPP;
> +	struct sock *sk = sk_vsock(vsk);
> +	struct virtio_vsock_hdr *hdr;
> +	struct sk_buff *skb;
> +	size_t payload_len;
> +	int err;
> +
> +	if (flags & (MSG_OOB | MSG_ERRQUEUE))
> +		return -EOPNOTSUPP;
> +
> +	skb = skb_recv_datagram(sk, flags, &err);
> +	if (!skb)
> +		return err;
> +
> +	hdr = virtio_vsock_hdr(skb);
> +	payload_len = skb->len;
> +
> +	if (payload_len > len) {
> +		payload_len = len;
> +		msg->msg_flags |= MSG_TRUNC;
> +	}
> +
> +	err = skb_copy_datagram_iter(skb, 0, &msg->msg_iter, payload_len);
> +	if (err)
> +		goto out;
> +
> +	if (msg->msg_name) {
> +		DECLARE_SOCKADDR(struct sockaddr_vm *, vm_addr, msg->msg_name);
> +
> +		vsock_addr_init(vm_addr, le64_to_cpu(hdr->src_cid),
> +				le32_to_cpu(hdr->src_port));
> +		msg->msg_namelen = sizeof(*vm_addr);
> +	}
> +
> +	if (flags & MSG_TRUNC)
> +		err = skb->len;
> +	else
> +		err = payload_len;
> +
> +out:
> +	skb_free_datagram(sk, skb);
> +	return err;
>  }
>  EXPORT_SYMBOL_GPL(virtio_transport_dgram_dequeue);
>  
> @@ -1202,13 +1278,13 @@ EXPORT_SYMBOL_GPL(virtio_transport_stream_is_active);
>  int virtio_transport_dgram_bind(struct vsock_sock *vsk,
>  				struct sockaddr_vm *addr)
>  {
> -	return -EOPNOTSUPP;
> +	return vsock_bind_common(vsk, addr);
>  }
>  EXPORT_SYMBOL_GPL(virtio_transport_dgram_bind);
>  
>  bool virtio_transport_dgram_allow(struct vsock_sock *vsk, u32 cid, u32 port)
>  {
> -	return false;
> +	return true;
>  }
>  EXPORT_SYMBOL_GPL(virtio_transport_dgram_allow);
>  
> @@ -1246,7 +1322,17 @@ virtio_transport_dgram_enqueue(struct vsock_sock *vsk,
>  			       struct msghdr *msg,
>  			       size_t dgram_len)
>  {
> -	return -EOPNOTSUPP;
> +	struct virtio_vsock_pkt_info info = {
> +		.op = VIRTIO_VSOCK_OP_RW,
> +		.msg = msg,
> +		.pkt_len = dgram_len,
> +		.vsk = vsk,
> +		.remote_cid = remote_addr->svm_cid,
> +		.remote_port = remote_addr->svm_port,
> +		.net = sock_net(sk_vsock(vsk)),
> +	};
> +
> +	return virtio_transport_send_pkt_info(vsk, &info);
>  }
>  EXPORT_SYMBOL_GPL(virtio_transport_dgram_enqueue);
>  
> @@ -1771,7 +1857,8 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
>  static bool virtio_transport_valid_type(u16 type)
>  {
>  	return (type == VIRTIO_VSOCK_TYPE_STREAM) ||
> -	       (type == VIRTIO_VSOCK_TYPE_SEQPACKET);
> +	       (type == VIRTIO_VSOCK_TYPE_SEQPACKET) ||
> +	       (type == VIRTIO_VSOCK_TYPE_DGRAM);
>  }
>  
>  /* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex
> @@ -1805,6 +1892,41 @@ void virtio_transport_recv_pkt(struct virtio_transport *t,
>  		goto free_pkt;
>  	}
>  
> +	/* Dgram packets are delivered directly to bound sockets without
> +	 * going through the connection state machine. Undeliverable
> +	 * datagrams are silently dropped (no RST).
> +	 */
> +	if (le16_to_cpu(hdr->type) == VIRTIO_VSOCK_TYPE_DGRAM) {
> +		if (le16_to_cpu(hdr->op) != VIRTIO_VSOCK_OP_RW)
> +			goto free_pkt;
> +
> +		sk = vsock_find_bound_socket_net(&dst, net);
> +
> +		if (!sk || sk->sk_type != SOCK_DGRAM) {
> +			if (sk)
> +				sock_put(sk);
> +			goto free_pkt;
> +		}
> +
> +		vsk = vsock_sk(sk);
> +		lock_sock(sk);
> +		if (sock_flag(sk, SOCK_DEAD) ||
> +		    vsk->transport != &t->transport ||
> +		    (sk->sk_socket->state != SS_UNCONNECTED &&
> +		     !vsock_check_source(vsk, &t->transport, &src))) {
> +			release_sock(sk);
> +			sock_put(sk);
> +			goto free_pkt;
> +		}
> +
> +		if (sock_queue_rcv_skb(sk, skb))
> +			kfree_skb(skb);

I'd love to see the receive path be free of lock_sock the way that UDP
does.

My understanding from udp is that we can avoid the race with
close/SOCK_DEAD by using SOCK_RCU_FREE and putting this receive in an
rcu read-side section. I think this makes sk->sk_socket->state safe
inside the RCU read side section too.

I think vsock_check_source() in a later patch goes away with
virtio_transport_dgram_source_allow(), so I think maybe that patch
should come before this?

Best,
Bobby

> +
> +		release_sock(sk);
> +		sock_put(sk);
> +		return;
> +	}
> +
>  	/* The socket must be in connected or bound table
>  	 * otherwise send reset back
>  	 */
> diff --git a/net/vmw_vsock/vsock_bpf.c b/net/vmw_vsock/vsock_bpf.c
> index 9049d2648646..296e1fa7970b 100644
> --- a/net/vmw_vsock/vsock_bpf.c
> +++ b/net/vmw_vsock/vsock_bpf.c
> @@ -161,7 +161,8 @@ int vsock_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore
>  	if (!vsk->transport)
>  		return -ENODEV;
>  
> -	if (!vsk->transport->read_skb)
> +	/* Datagram receive is not implemented by the sockmap callbacks. */
> +	if (sk->sk_type == SOCK_DGRAM || !vsk->transport->read_skb)
>  		return -EOPNOTSUPP;
>  
>  	vsock_bpf_check_needs_rebuild(psock->sk_proto);
> 
> -- 
> 2.56.0
> 

  reply	other threads:[~2026-11-03 20:06 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-28 16:04 [PATCH RFC 0/8] vsock: add datagram support to virtio and vhost Sergio Lopez
2026-10-28 16:04 ` [PATCH RFC 1/8] vsock: expose the core port allocator to transports Sergio Lopez
2026-10-28 16:04 ` [PATCH RFC 2/8] vsock: report datagram receive and send queue state Sergio Lopez
2026-10-28 16:04 ` [PATCH RFC 3/8] vsock/virtio: implement the datagram data path Sergio Lopez
2026-11-03 20:05   ` Bobby Eshleman [this message]
2026-11-03 20:15     ` Bobby Eshleman
2026-10-28 16:04 ` [PATCH RFC 4/8] vsock/virtio: negotiate datagram support on the guest Sergio Lopez
2026-10-28 16:04 ` [PATCH RFC 5/8] vhost/vsock: negotiate datagram support with guests Sergio Lopez
2026-10-28 16:04 ` [PATCH RFC 6/8] vsock: allow datagrams to use directional transports Sergio Lopez
2026-10-28 16:04 ` [PATCH RFC 7/8] vsock: preserve host-to-guest datagram boundaries Sergio Lopez
2026-11-02 22:29   ` Bobby Eshleman
2026-10-28 16:04 ` [PATCH RFC 8/8] vsock: add datagram tests to vsock_test Sergio Lopez
2026-10-28 17:25 ` [PATCH RFC 0/8] vsock: add datagram support to virtio and vhost Alexei Starovoitov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=auo+nf3+0Mdm8vpi@devvm29614.prn0.facebook.com \
    --to=bobbyeshleman@meta.com \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=bpf@vger.kernel.org \
    --cc=bryan-bt.tan@broadcom.com \
    --cc=davem@davemloft.net \
    --cc=decui@microsoft.com \
    --cc=edumazet@kernel.org \
    --cc=eperezma@redhat.com \
    --cc=haiyangz@microsoft.com \
    --cc=horms@kernel.org \
    --cc=jasowangio@gmail.com \
    --cc=kuba@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-hyperv@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sgarzare@redhat.com \
    --cc=slp@redhat.com \
    --cc=stefanha@redhat.com \
    --cc=virtualization@lists.linux.dev \
    --cc=vishnu.dasa@broadcom.com \
    --cc=wei.liu@kernel.org \
    --cc=xuanzhuo@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®