This is an AI-generated review of your patch. The human sending this email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html --- vsock: add G2H fallback for CIDs not owned by H2G transport This commit enables G2H transport fallback for CIDs not claimed by the H2G transport in environments like Nitro Enclaves. It adds a per-netns sysctl net.vsock.g2h_fallback (default 1) and a has_remote_cid callback for transports to declare CID ownership. > The flag was introduced 6 years ago and I am still not aware of any tool This isn't a bug, but the timing is slightly inaccurate. VMADDR_FLAG_TO_HOST was introduced in commit caaf95e0f23f on 2020-12-14. As of March 2026, this is approximately 5 years and 3 months, not 6 years. > diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h > index 533d8e75f7bb..4e40063adab4 100644 > --- a/include/net/af_vsock.h > +++ b/include/net/af_vsock.h > @@ -179,6 +179,15 @@ struct vsock_transport { > /* Addressing. */ > u32 (*get_local_cid)(void); > > + /* Check if this transport serves a specific remote CID. > + * For H2G transports: return true if the CID belongs to a registered > + * guest. If not implemented, all CIDs > VMADDR_CID_HOST go to H2G. > + * For G2H transports: return true if the transport can reach arbitrary > + * CIDs via the hypervisor (i.e. supports the fallback overlay). VMCI > + * does not implement this as it only serves CIDs 0 and 2. > + */ > + bool (*has_remote_cid)(struct vsock_sock *vsk, u32 remote_cid); > + The G2H transport description doesn't mention a critical consequence: G2H transports that do not implement has_remote_cid (like hyperv_transport) will never receive fallback traffic even with g2h_fallback=1, because the fallback branch in vsock_assign_transport() requires transport_g2h->has_remote_cid to be non-NULL. Should the comment clarify this requirement for G2H transports to participate in fallback? [ ... ] > diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c > index f0ab2f13e9db..cc4b225250b9 100644 > --- a/net/vmw_vsock/af_vsock.c > +++ b/net/vmw_vsock/af_vsock.c > @@ -545,9 +545,13 @@ static void vsock_deassign_transport(struct vsock_sock > *vsk) > * The vsk->remote_addr is used to decide which transport to use: > * - remote CID == VMADDR_CID_LOCAL or g2h->local_cid or VMADDR_CID_HOST if > * g2h is not loaded, will use local transport; > - * - remote CID <= VMADDR_CID_HOST or h2g is not loaded or remote flags > field > - * includes VMADDR_FLAG_TO_HOST flag value, will use guest->host > transport; > - * - remote CID > VMADDR_CID_HOST will use host->guest transport; > + * - remote CID <= VMADDR_CID_HOST or remote flags field includes > + * VMADDR_FLAG_TO_HOST, will use guest->host transport; > + * - remote CID > VMADDR_CID_HOST and h2g is loaded and h2g claims that CID, > + * will use host->guest transport; > + * - h2g not loaded or h2g does not claim that CID and g2h claims the CID > via > + * has_remote_cid, will use guest->host transport (when g2h_fallback=1) > + * - anything else goes to h2g or returns -ENODEV if no h2g is available > */ > int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) > { The commit message states this patch extends the existing behavior: "When no H2G transport is loaded, vsock currently routes all CIDs to the G2H transport...Extend that existing behavior: when an H2G transport is loaded but does not claim a given CID, the connection falls back to G2H in the same way." Does this accurately describe what the patch does? > @@ -581,11 +585,21 @@ int vsock_assign_transport(struct vsock_sock *vsk, > struct vsock_sock *psk) > case SOCK_SEQPACKET: > if (vsock_use_local_transport(remote_cid)) > new_transport = transport_local; > - else if (remote_cid <= VMADDR_CID_HOST || !transport_h2g || > + else if (remote_cid <= VMADDR_CID_HOST || > (remote_flags & VMADDR_FLAG_TO_HOST)) > new_transport = transport_g2h; > - else > + 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)) { > + vsk->remote_addr.svm_flags |= VMADDR_FLAG_TO_HOST; > + new_transport = transport_g2h; > + } else { > new_transport = transport_h2g; > + } > break; The old code had `!transport_h2g` in the second else-if condition at line -583, which routed all CID > VMADDR_CID_HOST traffic to transport_g2h when no H2G transport was loaded. The new code removes this check. When transport_h2g is NULL (no H2G transport loaded) and the G2H transport does not implement has_remote_cid (as is the case for VMCI and Hyper-V transports), what happens? The G2H fallback branch at line +596 requires `transport_g2h->has_remote_cid` to be non-NULL. If it's NULL, the short-circuit evaluation skips this branch and executes the final else at line +601, setting `new_transport = transport_h2g` (which is NULL), ultimately returning -ENODEV. The commit message explicitly states the intent to preserve the existing no-H2G fallback behavior. Does this implementation break it for G2H transports that do not implement the new optional has_remote_cid callback? This affects VMCI and Hyper-V environments: when no H2G transport is loaded, CID > 2 connections that previously fell back to G2H now get ENODEV. [ ... ] > @@ -2928,6 +2952,7 @@ static void vsock_net_init(struct net *net) > net->vsock.mode = > vsock_net_child_mode(current->nsproxy->net_ns); > > net->vsock.child_ns_mode = net->vsock.mode; > + net->vsock.g2h_fallback = 1; > } Stefano Garzarella raised a question in v3 about the sysctl inheritance policy for g2h_fallback: should it inherit from the parent namespace or always default to 1 in all namespaces? He cc'd net maintainers (Michael, Paolo, Jakub) for guidance: https://lore.kernel.org/all/aahRzq5vS76rPI28@sgarzare-redhat/ The current code always defaults to 1 for all namespaces (including child namespaces), which differs from how ns_mode is handled (which inherits from parent). Was there a resolution to this question? [ ... ] > diff --git a/net/vmw_vsock/virtio_transport.c > b/net/vmw_vsock/virtio_transport.c > index 77fe5b7b066c..57f2d6ec3ffc 100644 > --- a/net/vmw_vsock/virtio_transport.c > +++ b/net/vmw_vsock/virtio_transport.c > @@ -547,11 +547,18 @@ bool virtio_transport_stream_allow(struct vsock_sock > *vsk, u32 cid, u32 port) > static bool virtio_transport_seqpacket_allow(struct vsock_sock *vsk, > u32 remote_cid); > > +static bool virtio_transport_has_remote_cid(struct vsock_sock *vsk, u32 cid) > +{ > + /* The CID could be implemented by the host. Always assume it is. */ > + return true; > +} > + The comment says "always assume it is" implemented by the host. Is this a verifiable fact or a design choice? The guest cannot know what CIDs the host or hypervisor can reach, so this is a reasonable design choice. However, it also means all unclaimed CIDs fall back to G2H when virtio is the G2H transport, which could silently create host vsock traffic for typos or invalid CIDs.

