mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sergio Lopez <slp@redhat.com>
To: "Stefano Garzarella" <sgarzare@redhat.com>,
	"Bobby Eshleman" <bobbyeshleman@meta.com>,
	"Alexei Starovoitov" <ast@kernel.org>,
	"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>,
	"Shuah Khan" <skhan@linuxfoundation.org>,
	"Randy Dunlap" <rdunlap@infradead.org>
Cc: 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,
	Jonathan Corbet <corbet@lwn.net>,
	 linux-doc@vger.kernel.org, Sergio Lopez <slp@redhat.com>
Subject: [PATCH RFC v2 6/8] vsock: allow datagrams to use directional transports
Date: Fri, 13 Nov 2026 13:47:39 +0100	[thread overview]
Message-ID: <20261113-vsock-dgram-support-v2-6-bacfc85b71ce@redhat.com> (raw)
In-Reply-To: <20261113-vsock-dgram-support-v2-0-bacfc85b71ce@redhat.com>

Use the datagram fallback transport to own sockets that need transport-
specific bind state. VMCI needs this ownership to create and destroy its
receive handle. Without a fallback, initialize socket state through a
directional transport or loopback; use loopback if a directional transport
does not support datagrams. Hyper-V still rejects datagrams.

Share local, guest-to-host, host-to-guest, and parent-fallback route
selection with stream and seqpacket sockets. Choose a capable directional
transport for each datagram destination and use VMCI when none can serve
the peer. Keep VMCI as the socket owner across connect and send calls so
changing destinations cannot destroy its receive handle. Preserve parent
routing in returned addresses and when connecting through the guest-to-host
fallback. A host CID remains a loopback alias when the guest transport has
no active device.

Reserve VMCI-bound ports in the core table as well as in VMCI so virtio
and vhost can deliver to the same socket. Undo the core bind if VMCI handle
creation fails, and retry ephemeral ports that collide with VMCI resources.
Queue only datagram payloads with common source metadata in both receive
paths. Read the shared queue directly in core recvmsg() and report payload
size through SIOCINQ. Preserve the virtio TO_HOST source flag, the VMCI
source CID and port, peeking, truncation, and socket filtering.

Allow virtio datagram sends from a VMCI-owned socket without interpreting
VMCI private state as virtio state. The skb's socket ownership tracks send
memory regardless of which transport owns the socket. Per-send capability
checks still reject host traffic when virtio datagrams were not negotiated.

Check connected sources against the peer's selected route and exact CID
and port, including on loopback. Wildcard loopback senders use the
addressed local CID; explicit bindings retain their own CID. Reject
loopback source bindings whose reply address selects another transport.
Use a copy of the peer address during connected sends so a temporary
parent fallback does not pin later sends to the host. Remove sockets from
the core tables when transport initialization fails.

Paired stream, seqpacket, and datagram tests pass with virtio/vhost.
Datagram tests also pass with a temporary VMCI-like fallback owner. The
fallback tests cover mixed send and receive, VMCI-style bind rollback, and
an unclaimed destination. A child-disappearance reproducer confirms parent
fallback and direct-route recovery. VMCI and Hyper-V objects build; real
VMCI hardware has not been exercised.

Link: https://lore.kernel.org/all/DMGNAV67LK3F.2FNLTD5NVHDEA@gmail.com/
Signed-off-by: Sergio Lopez <slp@redhat.com>
---
 Documentation/admin-guide/sysctl/net.rst |   8 +-
 drivers/vhost/vsock.c                    |   2 +-
 include/linux/virtio_vsock.h             |   9 +-
 include/net/af_vsock.h                   |  29 ++-
 net/vmw_vsock/af_vsock.c                 | 306 ++++++++++++++++++++++++++-----
 net/vmw_vsock/hyperv_transport.c         |  11 +-
 net/vmw_vsock/virtio_transport.c         |   2 +-
 net/vmw_vsock/virtio_transport_common.c  | 113 ++++++------
 net/vmw_vsock/vmci_transport.c           | 124 ++++---------
 net/vmw_vsock/vsock_loopback.c           |   2 +-
 10 files changed, 390 insertions(+), 216 deletions(-)

diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst
index fe43e8595958..30d81128fd29 100644
--- a/Documentation/admin-guide/sysctl/net.rst
+++ b/Documentation/admin-guide/sysctl/net.rst
@@ -586,9 +586,11 @@ reachable through the hypervisor (e.g. Nitro Enclaves) to address both using
 a single CID space, without requiring applications to set
 ``VMADDR_FLAG_TO_HOST``.
 
-When the fallback is taken, ``VMADDR_FLAG_TO_HOST`` is automatically set on
-the remote address so that userspace can determine the path via
-``getpeername()``.
+When a connect falls back, ``VMADDR_FLAG_TO_HOST`` is automatically set on
+the connected peer address so that userspace can determine the selected path
+via ``getpeername()``. A datagram send on an existing connection can also fall
+back; in that case the flag is set only on the per-send destination. Later
+sends can use H2G again if it takes ownership of the destination CID.
 
 Note: With this sysctl enabled, user space that attempts to talk to a guest
 CID which is not implemented by the H2G transport will create host vsock
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 7971f6f0b6a2..f4fb2ac732f5 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -462,9 +462,9 @@ static struct virtio_transport vhost_transport = {
 		.cancel_pkt               = vhost_transport_cancel_pkt,
 
 		.dgram_enqueue            = virtio_transport_dgram_enqueue,
-		.dgram_dequeue            = virtio_transport_dgram_dequeue,
 		.dgram_bind               = virtio_transport_dgram_bind,
 		.dgram_allow              = vhost_transport_dgram_allow,
+		.dgram_transport_match    = virtio_transport_dgram_transport_match,
 
 		.stream_enqueue           = virtio_transport_stream_enqueue,
 		.stream_dequeue           = virtio_transport_stream_dequeue,
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index f91704731057..16b869085a0a 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -12,6 +12,7 @@
 struct virtio_vsock_skb_cb {
 	bool reply;
 	bool tap_delivered;
+	bool to_host;
 	u32 offset;
 };
 
@@ -171,6 +172,7 @@ struct virtio_vsock_sock {
 
 struct virtio_vsock_pkt_info {
 	u32 remote_cid, remote_port;
+	const struct virtio_transport *t_ops;
 	struct vsock_sock *vsk;
 	struct msghdr *msg;
 	struct net *net;
@@ -204,11 +206,6 @@ virtio_transport_stream_dequeue(struct vsock_sock *vsk,
 				size_t len,
 				int type);
 int
-virtio_transport_dgram_dequeue(struct vsock_sock *vsk,
-			       struct msghdr *msg,
-			       size_t len, int flags);
-
-int
 virtio_transport_seqpacket_enqueue(struct vsock_sock *vsk,
 				   struct msghdr *msg,
 				   size_t len);
@@ -261,6 +258,7 @@ bool virtio_transport_stream_allow(struct vsock_sock *vsk, u32 cid, u32 port);
 int virtio_transport_dgram_bind(struct vsock_sock *vsk,
 				struct sockaddr_vm *addr);
 bool virtio_transport_dgram_allow(struct vsock_sock *vsk, u32 cid, u32 port);
+bool virtio_transport_dgram_transport_match(const struct vsock_transport *t);
 
 int virtio_transport_connect(struct vsock_sock *vsk);
 
@@ -274,6 +272,7 @@ virtio_transport_stream_enqueue(struct vsock_sock *vsk,
 				size_t len);
 int
 virtio_transport_dgram_enqueue(struct vsock_sock *vsk,
+			       const struct vsock_transport *transport,
 			       struct sockaddr_vm *remote_addr,
 			       struct msghdr *msg,
 			       size_t len);
diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
index e4fbea3b0e46..a62e8076ee29 100644
--- a/include/net/af_vsock.h
+++ b/include/net/af_vsock.h
@@ -26,6 +26,13 @@ extern spinlock_t vsock_table_lock;
 #define vsock_sk(__sk)    ((struct vsock_sock *)__sk)
 #define sk_vsock(__vsk)   (&(__vsk)->sk)
 
+/* Datagrams from different transports share the socket receive queue. */
+struct vsock_dgram_skb_cb {
+	struct sockaddr_vm src;
+};
+
+#define VSOCK_DGRAM_SKB_CB(skb) ((struct vsock_dgram_skb_cb *)((skb)->cb))
+
 struct vsock_sock {
 	/* sk must be the first member. */
 	struct sock sk;
@@ -98,8 +105,8 @@ struct vsock_transport_send_notify_data {
 #define VSOCK_TRANSPORT_F_H2G		0x00000001
 /* Transport provides guest->host communication */
 #define VSOCK_TRANSPORT_F_G2H		0x00000002
-/* Transport provides DGRAM communication */
-#define VSOCK_TRANSPORT_F_DGRAM		0x00000004
+/* Transport provides fallback DGRAM communication and owns its endpoint */
+#define VSOCK_TRANSPORT_F_DGRAM_FALLBACK	0x00000004
 /* Transport provides local (loopback) communication */
 #define VSOCK_TRANSPORT_F_LOCAL		0x00000008
 
@@ -119,13 +126,15 @@ struct vsock_transport {
 
 	/* DGRAM. */
 	int (*dgram_bind)(struct vsock_sock *, struct sockaddr_vm *);
-	int (*dgram_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
-			     size_t len, int flags);
-	int (*dgram_enqueue)(struct vsock_sock *, struct sockaddr_vm *,
-			     struct msghdr *, size_t len);
+	int (*dgram_enqueue)(struct vsock_sock *vsk,
+			     const struct vsock_transport *transport,
+			     struct sockaddr_vm *remote_addr,
+			     struct msghdr *msg, size_t len);
 	bool (*dgram_allow)(struct vsock_sock *vsk, u32 cid, u32 port);
-	/* Optional payload length override, called with the receive queue locked. */
-	size_t (*dgram_payload_len)(const struct sk_buff *skb);
+	/* A fallback transport can share its datagram sockets with routed ones. */
+	bool dgram_fallback;
+	/* Optional: another transport can use this socket's datagram state. */
+	bool (*dgram_transport_match)(const struct vsock_transport *transport);
 
 	/* STREAM. */
 	/* TODO: stream_bind() */
@@ -223,6 +232,7 @@ void vsock_enqueue_accept(struct sock *listener, struct sock *connected);
 void vsock_pending_to_accept(struct sock *listener, struct sock *pending);
 void vsock_insert_connected(struct vsock_sock *vsk);
 int vsock_bind_common(struct vsock_sock *vsk, struct sockaddr_vm *addr);
+void vsock_unbind_common(struct vsock_sock *vsk);
 void vsock_remove_bound(struct vsock_sock *vsk);
 void vsock_remove_connected(struct vsock_sock *vsk);
 struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr);
@@ -242,6 +252,9 @@ void vsock_remove_sock(struct vsock_sock *vsk);
 void vsock_for_each_connected_socket(struct vsock_transport *transport,
 				     void (*fn)(struct sock *sk));
 int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk);
+const struct vsock_transport *
+vsock_dgram_get_transport(struct vsock_sock *vsk,
+			  struct sockaddr_vm *remote_addr);
 bool vsock_find_cid(unsigned int cid);
 void vsock_linger(struct sock *sk);
 
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index aef5389eeca2..7e52c7e5583c 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -132,6 +132,7 @@
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/cred.h>
+#include <linux/err.h>
 #include <linux/errqueue.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -198,8 +199,8 @@ struct proto vsock_proto = {
 static const struct vsock_transport *transport_h2g;
 /* Transport used for guest->host communication */
 static const struct vsock_transport *transport_g2h;
-/* Transport used for DGRAM communication */
-static const struct vsock_transport *transport_dgram;
+/* Transport owning fallback datagram endpoints */
+static const struct vsock_transport *transport_dgram_fallback;
 /* Transport used for local communication */
 static const struct vsock_transport *transport_local;
 static DEFINE_MUTEX(vsock_register_mutex);
@@ -568,6 +569,8 @@ EXPORT_SYMBOL_GPL(vsock_enqueue_accept);
 
 static bool vsock_use_local_transport(unsigned int remote_cid)
 {
+	u32 local_cid;
+
 	lockdep_assert_held(&vsock_register_mutex);
 
 	if (!transport_local)
@@ -576,11 +579,50 @@ static bool vsock_use_local_transport(unsigned int remote_cid)
 	if (remote_cid == VMADDR_CID_LOCAL)
 		return true;
 
-	if (transport_g2h) {
-		return remote_cid == transport_g2h->get_local_cid();
-	} else {
-		return remote_cid == VMADDR_CID_HOST;
-	}
+	local_cid = transport_g2h ? transport_g2h->get_local_cid() :
+		VMADDR_CID_ANY;
+	if (local_cid == VMADDR_CID_ANY)
+		local_cid = VMADDR_CID_HOST;
+
+	return remote_cid == local_cid;
+}
+
+/* Select a route without changing socket ownership. The caller holds
+ * vsock_register_mutex and pins the returned transport before releasing it.
+ */
+static const struct vsock_transport *
+vsock_select_transport(struct vsock_sock *vsk,
+		       const struct sockaddr_vm *remote_addr,
+		       const struct vsock_transport *dgram_owner,
+		       bool *to_host)
+{
+	struct sock *sk = sk_vsock(vsk);
+	u32 cid = remote_addr->svm_cid;
+
+	lockdep_assert_held(&vsock_register_mutex);
+	*to_host = false;
+
+	if (vsock_use_local_transport(cid))
+		return transport_local;
+	/* VMCI may use a different local CID from the virtio transports. */
+	if (dgram_owner && dgram_owner->dgram_fallback &&
+	    cid == dgram_owner->get_local_cid())
+		return dgram_owner;
+	if (cid <= VMADDR_CID_HOST ||
+	    (remote_addr->svm_flags & VMADDR_FLAG_TO_HOST))
+		return transport_g2h;
+	if (transport_h2g &&
+	    (!transport_h2g->has_remote_cid ||
+	     transport_h2g->has_remote_cid(vsk, cid)))
+		return transport_h2g;
+	if (sock_net(sk)->vsock.g2h_fallback && transport_g2h &&
+	    transport_g2h->has_remote_cid &&
+	    transport_g2h->has_remote_cid(vsk, cid)) {
+		*to_host = true;
+		return transport_g2h;
+	}
+
+	return transport_h2g;
 }
 
 static void vsock_deassign_transport(struct vsock_sock *vsk)
@@ -612,9 +654,11 @@ static void vsock_deassign_transport(struct vsock_sock *vsk)
 int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
 {
 	const struct vsock_transport *new_transport;
+	const struct vsock_transport *fallback_transport = NULL;
+	const struct vsock_transport *local_fallback = NULL;
 	struct sock *sk = sk_vsock(vsk);
 	unsigned int remote_cid = vsk->remote_addr.svm_cid;
-	__u8 remote_flags;
+	bool to_host;
 	int ret;
 
 	/* If the packet is coming with the source and destination CIDs higher
@@ -629,33 +673,28 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
 	    vsk->remote_addr.svm_cid > VMADDR_CID_HOST)
 		vsk->remote_addr.svm_flags |= VMADDR_FLAG_TO_HOST;
 
-	remote_flags = vsk->remote_addr.svm_flags;
-
 	mutex_lock(&vsock_register_mutex);
 
 	switch (sk->sk_type) {
 	case SOCK_DGRAM:
-		new_transport = transport_dgram;
+		/* VMCI must own bind() to create its receive handle, even when
+		 * directional transports serve individual destinations.
+		 */
+		if (transport_dgram_fallback)
+			new_transport = transport_dgram_fallback;
+		else if (transport_g2h)
+			new_transport = transport_g2h;
+		else if (transport_h2g)
+			new_transport = transport_h2g;
+		else
+			new_transport = transport_local;
 		break;
 	case SOCK_STREAM:
 	case SOCK_SEQPACKET:
-		if (vsock_use_local_transport(remote_cid))
-			new_transport = transport_local;
-		else if (remote_cid <= VMADDR_CID_HOST ||
-			 (remote_flags & VMADDR_FLAG_TO_HOST))
-			new_transport = transport_g2h;
-		else if (transport_h2g &&
-			 (!transport_h2g->has_remote_cid ||
-			  transport_h2g->has_remote_cid(vsk, remote_cid)))
-			new_transport = transport_h2g;
-		else if (sock_net(sk)->vsock.g2h_fallback &&
-			 transport_g2h && transport_g2h->has_remote_cid &&
-			 transport_g2h->has_remote_cid(vsk, remote_cid)) {
+		new_transport = vsock_select_transport(vsk, &vsk->remote_addr,
+						       NULL, &to_host);
+		if (to_host)
 			vsk->remote_addr.svm_flags |= VMADDR_FLAG_TO_HOST;
-			new_transport = transport_g2h;
-		} else {
-			new_transport = transport_h2g;
-		}
 		break;
 	default:
 		ret = -ESOCKTNOSUPPORT;
@@ -674,6 +713,17 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
 		ret = -ENODEV;
 		goto err;
 	}
+	if (sk->sk_type == SOCK_DGRAM && !transport_dgram_fallback &&
+	    new_transport == transport_g2h && transport_h2g &&
+	    transport_h2g != new_transport &&
+	    try_module_get(transport_h2g->module))
+		fallback_transport = transport_h2g;
+	/* Loopback can own datagram state when directional transports cannot. */
+	if (sk->sk_type == SOCK_DGRAM && !transport_dgram_fallback &&
+	    new_transport != transport_local && transport_local &&
+	    transport_local != fallback_transport &&
+	    try_module_get(transport_local->module))
+		local_fallback = transport_local;
 
 	/* It's safe to release the mutex after a successful try_module_get().
 	 * Whichever transport `new_transport` points at, it won't go away until
@@ -710,6 +760,22 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
 	}
 
 	ret = new_transport->init(vsk, psk);
+	if (ret == -ESOCKTNOSUPPORT && fallback_transport) {
+		module_put(new_transport->module);
+		new_transport = fallback_transport;
+		fallback_transport = NULL;
+		ret = new_transport->init(vsk, psk);
+	}
+	if (ret == -ESOCKTNOSUPPORT && local_fallback) {
+		module_put(new_transport->module);
+		new_transport = local_fallback;
+		local_fallback = NULL;
+		ret = new_transport->init(vsk, psk);
+	}
+	if (fallback_transport)
+		module_put(fallback_transport->module);
+	if (local_fallback)
+		module_put(local_fallback->module);
 	if (ret) {
 		module_put(new_transport->module);
 		return ret;
@@ -724,6 +790,101 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
 }
 EXPORT_SYMBOL_GPL(vsock_assign_transport);
 
+/**
+ * vsock_dgram_get_transport - select a transport for a datagram destination
+ * @vsk: socket whose datagram state will be used
+ * @remote_addr: destination address
+ *
+ * The caller must hold the socket lock and release the returned transport's
+ * module reference after use. A datagram fallback owns its socket's binding,
+ * but a directional transport takes precedence when it can reach the peer.
+ * Parent fallback sets VMADDR_FLAG_TO_HOST to preserve that route on connect.
+ *
+ * Return: a referenced transport or an ERR_PTR on failure.
+ */
+const struct vsock_transport *
+vsock_dgram_get_transport(struct vsock_sock *vsk,
+			  struct sockaddr_vm *remote_addr)
+{
+	const struct vsock_transport *owner = vsk->transport;
+	const struct vsock_transport *transport;
+	u32 cid = remote_addr->svm_cid;
+	u32 local_cid;
+	bool to_host = false;
+	bool shared;
+	int err = -ENODEV;
+
+	if (!owner)
+		return ERR_PTR(-ENODEV);
+
+	mutex_lock(&vsock_register_mutex);
+	shared = owner->dgram_transport_match || owner->dgram_fallback;
+	if (!shared)
+		transport = owner;
+	else
+		transport = vsock_select_transport(vsk, remote_addr, owner,
+						   &to_host);
+
+	if (owner->dgram_fallback && transport != owner &&
+	    (!transport || !transport->dgram_transport_match ||
+	     !transport->dgram_transport_match(transport) ||
+	     !transport->dgram_allow ||
+	     !transport->dgram_allow(vsk, cid, remote_addr->svm_port))) {
+		transport = owner;
+		to_host = false;
+	}
+	if (owner->dgram_fallback && transport != owner &&
+	    transport->get_local_cid() != VMADDR_CID_LOCAL &&
+	    vsk->local_addr.svm_cid != VMADDR_CID_ANY &&
+	    vsk->local_addr.svm_cid != transport->get_local_cid()) {
+		transport = owner;
+		to_host = false;
+	}
+
+	if (!transport)
+		goto out;
+	if (owner->dgram_transport_match &&
+	    !owner->dgram_transport_match(transport)) {
+		err = -ESOCKTNOSUPPORT;
+		goto out;
+	}
+	/* Loopback source addresses must route replies back to loopback. */
+	if (shared && transport == transport_local &&
+	    vsk->local_addr.svm_cid != VMADDR_CID_ANY &&
+	    !vsock_use_local_transport(vsk->local_addr.svm_cid)) {
+		err = -EADDRNOTAVAIL;
+		goto out;
+	}
+	if (!try_module_get(transport->module))
+		goto out;
+	mutex_unlock(&vsock_register_mutex);
+
+	if (shared) {
+		local_cid = transport->get_local_cid();
+		if (vsk->local_addr.svm_cid != VMADDR_CID_ANY &&
+		    local_cid != VMADDR_CID_LOCAL &&
+		    vsk->local_addr.svm_cid != local_cid) {
+			err = -EADDRNOTAVAIL;
+			goto put_transport;
+		}
+	}
+	if (!transport->dgram_allow(vsk, cid, remote_addr->svm_port)) {
+		err = -EINVAL;
+		goto put_transport;
+	}
+	if (to_host)
+		remote_addr->svm_flags |= VMADDR_FLAG_TO_HOST;
+	return transport;
+
+put_transport:
+	module_put(transport->module);
+	return ERR_PTR(err);
+out:
+	mutex_unlock(&vsock_register_mutex);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(vsock_dgram_get_transport);
+
 /*
  * Provide safe access to static transport_{h2g,g2h,dgram,local} callbacks.
  * Otherwise we may race with module removal. Do not use on `vsk->transport`.
@@ -924,6 +1085,17 @@ int vsock_bind_common(struct vsock_sock *vsk, struct sockaddr_vm *addr)
 }
 EXPORT_SYMBOL_GPL(vsock_bind_common);
 
+/* Undo a transport binding that could not be completed after reserving a port. */
+void vsock_unbind_common(struct vsock_sock *vsk)
+{
+	spin_lock_bh(&vsock_table_lock);
+	__vsock_remove_bound(vsk);
+	vsock_addr_unbind(&vsk->local_addr);
+	__vsock_insert_bound(vsock_unbound_sockets, vsk);
+	spin_unlock_bh(&vsock_table_lock);
+}
+EXPORT_SYMBOL_GPL(vsock_unbind_common);
+
 static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr)
 {
 	struct vsock_sock *vsk = vsock_sk(sk);
@@ -1055,7 +1227,7 @@ static void __vsock_release(struct sock *sk, int level)
 
 	if (vsk->transport)
 		vsk->transport->release(vsk);
-	else if (sock_type_connectible(sk->sk_type))
+	else
 		vsock_remove_sock(vsk);
 
 	sock_orphan(sk);
@@ -1468,6 +1640,7 @@ static int vsock_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 	struct sock *sk;
 	struct vsock_sock *vsk;
 	struct sockaddr_vm *remote_addr;
+	struct sockaddr_vm connected_addr;
 	const struct vsock_transport *transport;
 
 	if (msg->msg_flags & MSG_OOB)
@@ -1498,7 +1671,8 @@ static int vsock_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 		 */
 
 		if (remote_addr->svm_cid == VMADDR_CID_ANY)
-			remote_addr->svm_cid = transport->get_local_cid();
+			remote_addr->svm_cid = transport->dgram_transport_match ?
+				VMADDR_CID_LOCAL : transport->get_local_cid();
 
 		if (!vsock_addr_bound(remote_addr)) {
 			err = -EINVAL;
@@ -1508,27 +1682,32 @@ static int vsock_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 		remote_addr = &vsk->remote_addr;
 
 		if (remote_addr->svm_cid == VMADDR_CID_ANY)
-			remote_addr->svm_cid = transport->get_local_cid();
+			remote_addr->svm_cid = transport->dgram_transport_match ?
+				VMADDR_CID_LOCAL : transport->get_local_cid();
 
 		/* XXX Should connect() or this function ensure remote_addr is
 		 * bound?
 		 */
-		if (!vsock_addr_bound(&vsk->remote_addr)) {
+		if (!vsock_addr_bound(remote_addr)) {
 			err = -EINVAL;
 			goto out;
 		}
+		/* A fallback must not pin subsequent sends to the host. */
+		connected_addr = *remote_addr;
+		remote_addr = &connected_addr;
 	} else {
 		err = -EINVAL;
 		goto out;
 	}
 
-	if (!transport->dgram_allow(vsk, remote_addr->svm_cid,
-				    remote_addr->svm_port)) {
-		err = -EINVAL;
+	transport = vsock_dgram_get_transport(vsk, remote_addr);
+	if (IS_ERR(transport)) {
+		err = PTR_ERR(transport);
 		goto out;
 	}
 
-	err = transport->dgram_enqueue(vsk, remote_addr, msg, len);
+	err = transport->dgram_enqueue(vsk, transport, remote_addr, msg, len);
+	module_put(transport->module);
 
 out:
 	release_sock(sk);
@@ -1542,6 +1721,7 @@ static int vsock_dgram_connect(struct socket *sock,
 	struct sock *sk;
 	struct vsock_sock *vsk;
 	struct sockaddr_vm *remote_addr;
+	const struct vsock_transport *transport;
 
 	sk = sock->sk;
 	vsk = vsock_sk(sk);
@@ -1563,11 +1743,16 @@ static int vsock_dgram_connect(struct socket *sock,
 	if (err)
 		goto out;
 
-	if (!vsk->transport->dgram_allow(vsk, remote_addr->svm_cid,
-					 remote_addr->svm_port)) {
-		err = -EINVAL;
+	if (remote_addr->svm_cid == VMADDR_CID_ANY &&
+	    vsk->transport->dgram_transport_match)
+		remote_addr->svm_cid = VMADDR_CID_LOCAL;
+
+	transport = vsock_dgram_get_transport(vsk, remote_addr);
+	if (IS_ERR(transport)) {
+		err = PTR_ERR(transport);
 		goto out;
 	}
+	module_put(transport->module);
 
 	memcpy(&vsk->remote_addr, remote_addr, sizeof(vsk->remote_addr));
 	sock->state = SS_CONNECTED;
@@ -1591,9 +1776,35 @@ int __vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
 			  size_t len, int flags)
 {
 	struct sock *sk = sock->sk;
-	struct vsock_sock *vsk = vsock_sk(sk);
+	struct sk_buff *skb;
+	size_t copied;
+	int err;
+
+	if (flags & (MSG_OOB | MSG_ERRQUEUE))
+		return -EOPNOTSUPP;
+
+	skb = skb_recv_datagram(sk, flags, &err);
+	if (!skb)
+		return err;
+
+	copied = min_t(size_t, len, skb->len);
+	if (copied < skb->len)
+		msg->msg_flags |= MSG_TRUNC;
+
+	err = skb_copy_datagram_iter(skb, 0, &msg->msg_iter, copied);
+	if (err)
+		goto out;
 
-	return vsk->transport->dgram_dequeue(vsk, msg, len, flags);
+	if (msg->msg_name) {
+		memcpy(msg->msg_name, &VSOCK_DGRAM_SKB_CB(skb)->src,
+		       sizeof(struct sockaddr_vm));
+		msg->msg_namelen = sizeof(struct sockaddr_vm);
+	}
+
+	err = flags & MSG_TRUNC ? skb->len : copied;
+out:
+	skb_free_datagram(sk, skb);
+	return err;
 }
 
 int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -1641,10 +1852,7 @@ static int vsock_do_ioctl(struct socket *sock, unsigned int cmd,
 
 			spin_lock_bh(&sk->sk_receive_queue.lock);
 			skb = skb_peek(&sk->sk_receive_queue);
-			if (skb && vsk->transport->dgram_payload_len)
-				n_bytes = vsk->transport->dgram_payload_len(skb);
-			else
-				n_bytes = skb ? skb->len : 0;
+			n_bytes = skb ? skb->len : 0;
 			spin_unlock_bh(&sk->sk_receive_queue.lock);
 		} else {
 			n_bytes = vsock_stream_has_data(vsk);
@@ -3247,7 +3455,7 @@ int vsock_core_register(const struct vsock_transport *t, int features)
 
 	t_h2g = transport_h2g;
 	t_g2h = transport_g2h;
-	t_dgram = transport_dgram;
+	t_dgram = transport_dgram_fallback;
 	t_local = transport_local;
 
 	if (features & VSOCK_TRANSPORT_F_H2G) {
@@ -3266,7 +3474,7 @@ int vsock_core_register(const struct vsock_transport *t, int features)
 		t_g2h = t;
 	}
 
-	if (features & VSOCK_TRANSPORT_F_DGRAM) {
+	if (features & VSOCK_TRANSPORT_F_DGRAM_FALLBACK) {
 		if (t_dgram) {
 			err = -EBUSY;
 			goto err_busy;
@@ -3284,7 +3492,7 @@ int vsock_core_register(const struct vsock_transport *t, int features)
 
 	transport_h2g = t_h2g;
 	transport_g2h = t_g2h;
-	transport_dgram = t_dgram;
+	transport_dgram_fallback = t_dgram;
 	transport_local = t_local;
 
 err_busy:
@@ -3303,8 +3511,8 @@ void vsock_core_unregister(const struct vsock_transport *t)
 	if (transport_g2h == t)
 		transport_g2h = NULL;
 
-	if (transport_dgram == t)
-		transport_dgram = NULL;
+	if (transport_dgram_fallback == t)
+		transport_dgram_fallback = NULL;
 
 	if (transport_local == t)
 		transport_local = NULL;
diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c
index 855b15971c35..015c5371ea98 100644
--- a/net/vmw_vsock/hyperv_transport.c
+++ b/net/vmw_vsock/hyperv_transport.c
@@ -443,6 +443,9 @@ static int hvs_sock_init(struct vsock_sock *vsk, struct vsock_sock *psk)
 	struct hvsock *hvs;
 	struct sock *sk = sk_vsock(vsk);
 
+	if (sk->sk_type == SOCK_DGRAM)
+		return -ESOCKTNOSUPPORT;
+
 	hvs = kzalloc_obj(*hvs);
 	if (!hvs)
 		return -ENOMEM;
@@ -556,13 +559,8 @@ static int hvs_dgram_bind(struct vsock_sock *vsk, struct sockaddr_vm *addr)
 	return -EOPNOTSUPP;
 }
 
-static int hvs_dgram_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
-			     size_t len, int flags)
-{
-	return -EOPNOTSUPP;
-}
-
 static int hvs_dgram_enqueue(struct vsock_sock *vsk,
+			     const struct vsock_transport *transport,
 			     struct sockaddr_vm *remote, struct msghdr *msg,
 			     size_t dgram_len)
 {
@@ -871,7 +869,6 @@ static struct vsock_transport hvs_transport = {
 	.shutdown                 = hvs_shutdown,
 
 	.dgram_bind               = hvs_dgram_bind,
-	.dgram_dequeue            = hvs_dgram_dequeue,
 	.dgram_enqueue            = hvs_dgram_enqueue,
 	.dgram_allow              = hvs_dgram_allow,
 
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index fd10f20d7611..87a96e94c3c2 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -582,9 +582,9 @@ static struct virtio_transport virtio_transport = {
 		.cancel_pkt               = virtio_transport_cancel_pkt,
 
 		.dgram_bind               = virtio_transport_dgram_bind,
-		.dgram_dequeue            = virtio_transport_dgram_dequeue,
 		.dgram_enqueue            = virtio_transport_dgram_enqueue,
 		.dgram_allow              = virtio_transport_dgram_allow_check,
+		.dgram_transport_match    = virtio_transport_dgram_transport_match,
 
 		.stream_dequeue           = virtio_transport_stream_dequeue,
 		.stream_enqueue           = virtio_transport_stream_enqueue,
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 08baa1181ba6..3ef86f5eaf36 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -316,21 +316,30 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
 
 	info->type = virtio_transport_get_type(sk_vsock(vsk));
 
-	t_ops = virtio_transport_get_ops(vsk);
+	t_ops = info->t_ops ?: virtio_transport_get_ops(vsk);
 	if (unlikely(!t_ops))
 		return -EFAULT;
 
 	src_cid = t_ops->transport.get_local_cid();
 	src_port = vsk->local_addr.svm_port;
-	if (!info->remote_cid) {
+	if (info->type != VIRTIO_VSOCK_TYPE_DGRAM && !info->remote_cid) {
 		dst_cid	= vsk->remote_addr.svm_cid;
 		dst_port = vsk->remote_addr.svm_port;
 	} else {
 		dst_cid = info->remote_cid;
 		dst_port = info->remote_port;
 	}
+	/* Explicit loopback bindings keep their CID; wildcard bindings use
+	 * the addressed local CID so connected peers can compare exact CIDs.
+	 */
+	if (info->type == VIRTIO_VSOCK_TYPE_DGRAM &&
+	    src_cid == VMADDR_CID_LOCAL)
+		src_cid = vsk->local_addr.svm_cid == VMADDR_CID_ANY ?
+			dst_cid : vsk->local_addr.svm_cid;
 
-	/* Datagram sends use socket memory accounting instead of peer credits. */
+	/* Datagram sends use socket memory accounting, including when VMCI
+	 * owns the socket and vsk->trans contains VMCI state.
+	 */
 	vvs = info->type == VIRTIO_VSOCK_TYPE_DGRAM ? NULL : vsk->trans;
 
 	if (info->type == VIRTIO_VSOCK_TYPE_DGRAM) {
@@ -1013,55 +1022,6 @@ virtio_transport_seqpacket_enqueue(struct vsock_sock *vsk,
 }
 EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_enqueue);
 
-int
-virtio_transport_dgram_dequeue(struct vsock_sock *vsk,
-			       struct msghdr *msg,
-			       size_t len, int flags)
-{
-	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);
-
 s64 virtio_transport_stream_has_data(struct vsock_sock *vsk)
 {
 	struct virtio_vsock_sock *vvs = vsk->trans;
@@ -1271,6 +1231,13 @@ bool virtio_transport_dgram_allow(struct vsock_sock *vsk, u32 cid, u32 port)
 }
 EXPORT_SYMBOL_GPL(virtio_transport_dgram_allow);
 
+bool virtio_transport_dgram_transport_match(const struct vsock_transport *t)
+{
+	return t && t->dgram_transport_match ==
+		virtio_transport_dgram_transport_match;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_dgram_transport_match);
+
 int virtio_transport_connect(struct vsock_sock *vsk)
 {
 	struct virtio_vsock_pkt_info info = {
@@ -1301,12 +1268,14 @@ EXPORT_SYMBOL_GPL(virtio_transport_shutdown);
 
 int
 virtio_transport_dgram_enqueue(struct vsock_sock *vsk,
+			       const struct vsock_transport *transport,
 			       struct sockaddr_vm *remote_addr,
 			       struct msghdr *msg,
 			       size_t dgram_len)
 {
 	struct virtio_vsock_pkt_info info = {
 		.op = VIRTIO_VSOCK_OP_RW,
+		.t_ops = container_of(transport, struct virtio_transport, transport),
 		.msg = msg,
 		.pkt_len = dgram_len,
 		.vsk = vsk,
@@ -1844,6 +1813,33 @@ static bool virtio_transport_valid_type(u16 type)
 	       (type == VIRTIO_VSOCK_TYPE_DGRAM);
 }
 
+static bool
+virtio_transport_dgram_source_allow(struct vsock_sock *vsk,
+				    const struct vsock_transport *transport,
+				    const struct sockaddr_vm *src)
+{
+	const struct vsock_transport *peer_transport;
+	struct sockaddr_vm peer = vsk->remote_addr;
+	bool allow;
+
+	if ((!virtio_transport_dgram_transport_match(vsk->transport) &&
+	     !vsk->transport->dgram_fallback) ||
+	    !virtio_transport_dgram_transport_match(transport))
+		return false;
+	/* Shutdown preserves the peer; only disconnect removes it. */
+	if (sk_vsock(vsk)->sk_socket->state == SS_UNCONNECTED)
+		return true;
+
+	peer_transport = vsock_dgram_get_transport(vsk, &peer);
+	if (IS_ERR(peer_transport))
+		return false;
+	allow = peer_transport == transport &&
+		src->svm_port == vsk->remote_addr.svm_port &&
+		src->svm_cid == vsk->remote_addr.svm_cid;
+	module_put(peer_transport->module);
+	return allow;
+}
+
 /* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex
  * lock.
  */
@@ -1891,14 +1887,21 @@ void virtio_transport_recv_pkt(struct virtio_transport *t,
 		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))) {
+		    !virtio_transport_dgram_source_allow(vsk, &t->transport, &src)) {
 			release_sock(sk);
 			sock_put(sk);
 			goto free_pkt;
 		}
 
+		/* Loopback can hand the TX skb to its receiver. Release TX
+		 * ownership before replacing its private control block.
+		 */
+		skb_orphan(skb);
+		vsock_addr_init(&VSOCK_DGRAM_SKB_CB(skb)->src,
+				src.svm_cid, src.svm_port);
+		if (t->transport.get_local_cid() > VMADDR_CID_HOST)
+			VSOCK_DGRAM_SKB_CB(skb)->src.svm_flags =
+				VMADDR_FLAG_TO_HOST;
 		if (sock_queue_rcv_skb(sk, skb))
 			kfree_skb(skb);
 
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index 2b9493e987d1..3c02c9a5319b 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -629,18 +629,21 @@ static int vmci_transport_recv_dgram_cb(void *data, struct vmci_datagram *dg)
 	vsk = vsock_sk(sk);
 	if (!vmci_transport_allow_dgram(vsk, dg->src.context))
 		return VMCI_ERROR_NO_ACCESS;
+	if (dg->payload_size > VMCI_MAX_DG_PAYLOAD_SIZE)
+		return VMCI_ERROR_INVALID_ARGS;
 
-	size = VMCI_DG_SIZE(dg);
+	size = dg->payload_size;
 
-	/* Attach the packet to the socket's receive queue as an sk_buff. */
+	/* Queue only the payload, with transport-independent source metadata. */
 	skb = alloc_skb(size, GFP_ATOMIC);
 	if (!skb)
 		return VMCI_ERROR_NO_MEM;
 
 	/* sk_receive_skb() will do a sock_put(), so hold here. */
 	sock_hold(sk);
-	skb_put(skb, size);
-	memcpy(skb->data, dg, size);
+	skb_put_data(skb, VMCI_DG_PAYLOAD(dg), size);
+	vsock_addr_init(&VSOCK_DGRAM_SKB_CB(skb)->src,
+			dg->src.context, dg->src.resource);
 	sk_receive_skb(sk, skb, 0);
 
 	return VMCI_SUCCESS;
@@ -1690,39 +1693,49 @@ static void vmci_transport_release(struct vsock_sock *vsk)
 	}
 }
 
+#define VMCI_DGRAM_BIND_RETRIES 24
+
 static int vmci_transport_dgram_bind(struct vsock_sock *vsk,
 				     struct sockaddr_vm *addr)
 {
+	const bool auto_port = addr->svm_port == VMADDR_PORT_ANY;
 	u32 port;
 	u32 flags;
+	unsigned int i;
 	int err;
 
-	/* VMCI will select a resource ID for us if we provide
-	 * VMCI_INVALID_ID.
-	 */
-	port = addr->svm_port == VMADDR_PORT_ANY ?
-			VMCI_INVALID_ID : addr->svm_port;
-
-	if (port <= LAST_RESERVED_PORT && !capable(CAP_NET_BIND_SERVICE))
-		return -EACCES;
-
 	flags = addr->svm_cid == VMADDR_CID_ANY ?
 				VMCI_FLAG_ANYCID_DG_HND : 0;
 
-	err = vmci_transport_datagram_create_hnd(port, flags,
-						 vmci_transport_recv_dgram_cb,
-						 &vsk->sk,
-						 &vmci_trans(vsk)->dg_handle);
-	if (err < VMCI_SUCCESS)
-		return vmci_transport_error_to_vsock_error(err);
-	vsock_addr_init(&vsk->local_addr, addr->svm_cid,
-			vmci_trans(vsk)->dg_handle.resource);
+	/* Reserve the same port for VMCI and directional receive. A VMCI
+	 * resource may already occupy a core-selected ephemeral port.
+	 */
+	for (i = 0; i < VMCI_DGRAM_BIND_RETRIES; i++) {
+		err = vsock_bind_common(vsk, addr);
+		if (err)
+			return err;
 
-	return 0;
+		port = vsk->local_addr.svm_port;
+		err = vmci_transport_datagram_create_hnd(port, flags,
+							 vmci_transport_recv_dgram_cb,
+							 &vsk->sk,
+							 &vmci_trans(vsk)->dg_handle);
+		if (err >= VMCI_SUCCESS)
+			return 0;
+
+		vsock_unbind_common(vsk);
+		vmci_trans(vsk)->dg_handle = VMCI_INVALID_HANDLE;
+		if (!auto_port || (err != VMCI_ERROR_ALREADY_EXISTS &&
+				   err != VMCI_ERROR_DUPLICATE_ENTRY))
+			return vmci_transport_error_to_vsock_error(err);
+	}
+
+	return -EADDRNOTAVAIL;
 }
 
 static int vmci_transport_dgram_enqueue(
 	struct vsock_sock *vsk,
+	const struct vsock_transport *transport,
 	struct sockaddr_vm *remote_addr,
 	struct msghdr *msg,
 	size_t len)
@@ -1761,67 +1774,6 @@ static int vmci_transport_dgram_enqueue(
 	return err - sizeof(*dg);
 }
 
-static size_t vmci_transport_dgram_payload_len(const struct sk_buff *skb)
-{
-	if (skb->len < sizeof(struct vmci_datagram))
-		return 0;
-
-	return skb->len - sizeof(struct vmci_datagram);
-}
-
-static int vmci_transport_dgram_dequeue(struct vsock_sock *vsk,
-					struct msghdr *msg, size_t len,
-					int flags)
-{
-	int err;
-	struct vmci_datagram *dg;
-	size_t payload_len;
-	struct sk_buff *skb;
-
-	if (flags & MSG_OOB || flags & MSG_ERRQUEUE)
-		return -EOPNOTSUPP;
-
-	/* Retrieve the head sk_buff from the socket's receive queue. */
-	err = 0;
-	skb = skb_recv_datagram(&vsk->sk, flags, &err);
-	if (!skb)
-		return err;
-
-	dg = (struct vmci_datagram *)skb->data;
-	if (!dg)
-		/* err is 0, meaning we read zero bytes. */
-		goto out;
-
-	payload_len = dg->payload_size;
-	/* Ensure the sk_buff matches the payload size claimed in the packet. */
-	if (payload_len != skb->len - sizeof(*dg)) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	if (payload_len > len) {
-		payload_len = len;
-		msg->msg_flags |= MSG_TRUNC;
-	}
-
-	/* Place the datagram payload in the user's iovec. */
-	err = skb_copy_datagram_msg(skb, sizeof(*dg), msg, payload_len);
-	if (err)
-		goto out;
-
-	if (msg->msg_name) {
-		/* Provide the address of the sender. */
-		DECLARE_SOCKADDR(struct sockaddr_vm *, vm_addr, msg->msg_name);
-		vsock_addr_init(vm_addr, dg->src.context, dg->src.resource);
-		msg->msg_namelen = sizeof(*vm_addr);
-	}
-	err = payload_len;
-
-out:
-	skb_free_datagram(&vsk->sk, skb);
-	return err;
-}
-
 static bool vmci_transport_dgram_allow(struct vsock_sock *vsk, u32 cid,
 				       u32 port)
 {
@@ -2082,10 +2034,9 @@ static struct vsock_transport vmci_transport = {
 	.release = vmci_transport_release,
 	.connect = vmci_transport_connect,
 	.dgram_bind = vmci_transport_dgram_bind,
-	.dgram_dequeue = vmci_transport_dgram_dequeue,
-	.dgram_payload_len = vmci_transport_dgram_payload_len,
 	.dgram_enqueue = vmci_transport_dgram_enqueue,
 	.dgram_allow = vmci_transport_dgram_allow,
+	.dgram_fallback = true,
 	.stream_dequeue = vmci_transport_stream_dequeue,
 	.stream_enqueue = vmci_transport_stream_enqueue,
 	.stream_has_data = vmci_transport_stream_has_data,
@@ -2153,7 +2104,8 @@ static int __init vmci_transport_init(void)
 	/* Register only with dgram feature, other features (H2G, G2H) will be
 	 * registered when the first host or guest becomes active.
 	 */
-	err = vsock_core_register(&vmci_transport, VSOCK_TRANSPORT_F_DGRAM);
+	err = vsock_core_register(&vmci_transport,
+				  VSOCK_TRANSPORT_F_DGRAM_FALLBACK);
 	if (err < 0)
 		goto err_unsubscribe;
 
diff --git a/net/vmw_vsock/vsock_loopback.c b/net/vmw_vsock/vsock_loopback.c
index 8068d1b6e851..645b10843f86 100644
--- a/net/vmw_vsock/vsock_loopback.c
+++ b/net/vmw_vsock/vsock_loopback.c
@@ -74,9 +74,9 @@ static struct virtio_transport loopback_transport = {
 		.cancel_pkt               = vsock_loopback_cancel_pkt,
 
 		.dgram_bind               = virtio_transport_dgram_bind,
-		.dgram_dequeue            = virtio_transport_dgram_dequeue,
 		.dgram_enqueue            = virtio_transport_dgram_enqueue,
 		.dgram_allow              = virtio_transport_dgram_allow,
+		.dgram_transport_match    = virtio_transport_dgram_transport_match,
 
 		.stream_dequeue           = virtio_transport_stream_dequeue,
 		.stream_enqueue           = virtio_transport_stream_enqueue,

-- 
2.56.0


  parent reply	other threads:[~2026-11-13 12:50 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-13 12:47 [PATCH RFC v2 0/8] vsock: add datagram support to virtio and vhost Sergio Lopez
2026-11-13 12:47 ` [PATCH RFC v2 1/8] vsock: expose the core port allocator to transports Sergio Lopez
2026-11-13 12:47 ` [PATCH RFC v2 2/8] vsock: report datagram receive and send queue state Sergio Lopez
2026-11-13 12:47 ` [PATCH RFC v2 3/8] vsock/virtio: implement the datagram data path Sergio Lopez
2026-11-13 12:47 ` [PATCH RFC v2 4/8] vsock/virtio: negotiate datagram support on the guest Sergio Lopez
2026-11-13 12:47 ` [PATCH RFC v2 5/8] vhost/vsock: negotiate datagram support with guests Sergio Lopez
2026-11-13 12:47 ` Sergio Lopez [this message]
2026-11-13 12:47 ` [PATCH RFC v2 7/8] vsock: fragment datagrams across receive buffers Sergio Lopez
2026-11-13 12:47 ` [PATCH RFC v2 8/8] vsock: add datagram tests to vsock_test Sergio Lopez
2026-11-13 13:05 ` [PATCH RFC v2 0/8] vsock: add datagram support to virtio and vhost Michael S. Tsirkin

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=20261113-vsock-dgram-support-v2-6-bacfc85b71ce@redhat.com \
    --to=slp@redhat.com \
    --cc=ast@kernel.org \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=bobbyeshleman@meta.com \
    --cc=bpf@vger.kernel.org \
    --cc=bryan-bt.tan@broadcom.com \
    --cc=corbet@lwn.net \
    --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-doc@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=rdunlap@infradead.org \
    --cc=sgarzare@redhat.com \
    --cc=skhan@linuxfoundation.org \
    --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®