From: Bobby Eshleman <bobbyeshleman@gmail.com>
To: "Stefano Garzarella" <sgarzare@redhat.com>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@google.com>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Simon Horman" <horms@kernel.org>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Stefan Hajnoczi" <stefanha@redhat.com>,
"Michael S. Tsirkin" <mst@redhat.com>,
"Jason Wang" <jasowangio@gmail.com>,
"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
"Eugenio Pérez" <eperezma@redhat.com>,
"Shuah Khan" <shuah@kernel.org>,
"Randy Dunlap" <rdunlap@infradead.org>
Cc: virtualization@lists.linux.dev, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
kvm@vger.kernel.org, linux-kselftest@vger.kernel.org,
sargun@sargun.me, jlinbox@meta.com,
Bobby Eshleman <bobbyeshleman@meta.com>
Subject: [PATCH net-next 3/6] vsock/virtio: support guest device network namespace
Date: Wed, 02 Sep 2026 16:00:49 -0700 [thread overview]
Message-ID: <20260902-vsock-guest-ns-v1-3-9995383e9a8b@meta.com> (raw)
In-Reply-To: <20260902-vsock-guest-ns-v1-0-9995383e9a8b@meta.com>
From: Bobby Eshleman <bobbyeshleman@meta.com>
virtio-vsock did not have namespace support (the device was always
accessible to any global namespace).
Make the virtio-vsock device assignable to a namespace and initialize it
to init_net. Because virtio-vsock and init_net are both hardcoded to
global mode, nothing changes until the assign ioctl is issued.
When the device's local-mode namespace is being destroyed, received
packets are reset until new valid a namespace has been assigned and/or
automatically returned to, and the next RX batch begins (in
virtio_transport_rx_work). They are reset rather than dropped because
vsock does not retransmit, so a silent drop would leave the host waiting
for a timeout, and a connection request arriving in that window has no
socket whose teardown would tell it otherwise. This requires making
virtio_transport_reset_no_sock() available outside of the common code.
When a device is assigned to a namespace, every already established
vsock socket that is no longer able to reach the device is forcibly
reset. For that reason, adding new sockets to the connected table must
be performed atomically with regards to namespace assignment. This
ensures that when the socket is added to the connected table that it
actually passes the new reachability conditions set by ns assignment. If
it wins the race to the table and does NOT pass the reachability tests,
then the reset sweep will correctly catch it. This is the purpose
of the new helper 'vsock_maybe_set_connected()'.
Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
---
include/linux/virtio_vsock.h | 2 ++
net/vmw_vsock/virtio_transport.c | 28 ++++++++++++++++++++++------
net/vmw_vsock/virtio_transport_common.c | 28 +++++++++++++++++++++-------
3 files changed, 45 insertions(+), 13 deletions(-)
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index f91704731057..9c68ce1d7fb4 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -286,6 +286,8 @@ void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct sk_buff *
u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 wanted);
void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit);
void virtio_transport_deliver_tap_pkt(struct sk_buff *skb);
+int virtio_transport_reset_no_sock(const struct virtio_transport *t,
+ struct sk_buff *skb, struct net *net);
int virtio_transport_purge_skbs(void *vsk, struct sk_buff_head *list);
int virtio_transport_read_skb(struct vsock_sock *vsk, skb_read_actor_t read_actor);
int virtio_transport_notify_set_rcvlowat(struct vsock_sock *vsk, int val);
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index 4f9aa9c4c3aa..a453a4f828dc 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -540,9 +540,14 @@ static bool virtio_transport_msgzerocopy_allow(void)
return true;
}
+static bool virtio_transport_netns_assign_allow(void)
+{
+ return true;
+}
+
bool virtio_transport_stream_allow(struct vsock_sock *vsk, u32 cid, u32 port)
{
- return vsock_net_mode_global(vsk);
+ return vsock_g2h_net_reachable(sock_net(sk_vsock(vsk)));
}
static bool virtio_transport_seqpacket_allow(struct vsock_sock *vsk,
@@ -587,6 +592,7 @@ static struct virtio_transport virtio_transport = {
.seqpacket_has_data = virtio_transport_seqpacket_has_data,
.msgzerocopy_allow = virtio_transport_msgzerocopy_allow,
+ .netns_assign_allow = virtio_transport_netns_assign_allow,
.notify_poll_in = virtio_transport_notify_poll_in,
.notify_poll_out = virtio_transport_notify_poll_out,
@@ -616,7 +622,7 @@ virtio_transport_seqpacket_allow(struct vsock_sock *vsk, u32 remote_cid)
struct virtio_vsock *vsock;
bool seqpacket_allow;
- if (!vsock_net_mode_global(vsk))
+ if (!vsock_g2h_net_reachable(sock_net(sk_vsock(vsk))))
return false;
seqpacket_allow = false;
@@ -634,6 +640,9 @@ static void virtio_transport_rx_work(struct work_struct *work)
struct virtio_vsock *vsock =
container_of(work, struct virtio_vsock, rx_work);
struct virtqueue *vq;
+ struct net *net;
+
+ net = vsock_g2h_net_get();
mutex_lock(&vsock->rx_lock);
@@ -682,10 +691,14 @@ static void virtio_transport_rx_work(struct work_struct *work)
virtio_transport_deliver_tap_pkt(skb);
- /* Force virtio-transport into global mode since it
- * does not yet support local-mode namespacing.
- */
- virtio_transport_recv_pkt(&virtio_transport, skb, NULL);
+ if (unlikely(!net)) {
+ virtio_transport_reset_no_sock(
+ &virtio_transport, skb, &init_net);
+ kfree_skb(skb);
+ continue;
+ }
+
+ virtio_transport_recv_pkt(&virtio_transport, skb, net);
}
} while (!virtqueue_enable_cb(vq));
@@ -694,6 +707,9 @@ static void virtio_transport_rx_work(struct work_struct *work)
virtio_vsock_rx_fill(vsock);
out_nofill:
mutex_unlock(&vsock->rx_lock);
+
+ if (net)
+ put_net(net);
}
static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 88df82364f77..313ef263fd2d 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -1315,8 +1315,8 @@ static int virtio_transport_reset(struct vsock_sock *vsk,
* loopback, this is the namespace of the socket. For vhost, this is the
* namespace of the VM (i.e., vhost_vsock).
*/
-static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
- struct sk_buff *skb, struct net *net)
+int virtio_transport_reset_no_sock(const struct virtio_transport *t,
+ struct sk_buff *skb, struct net *net)
{
struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
struct virtio_vsock_pkt_info info = {
@@ -1355,6 +1355,7 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
return t->send_pkt(reply, net);
}
+EXPORT_SYMBOL_GPL(virtio_transport_reset_no_sock);
/* This function should be called with sk_lock held and SOCK_DONE set */
static void virtio_transport_remove_sock(struct vsock_sock *vsk)
@@ -1478,9 +1479,14 @@ virtio_transport_recv_connecting(struct sock *sk,
switch (le16_to_cpu(hdr->op)) {
case VIRTIO_VSOCK_OP_RESPONSE:
- sk->sk_state = TCP_ESTABLISHED;
+ /* An assign cannot see a socket that is not connected yet. */
+ if (!vsock_maybe_set_connected(vsk)) {
+ skerr = ECONNRESET;
+ err = -ENETUNREACH;
+ goto destroy;
+ }
+
sk->sk_socket->state = SS_CONNECTED;
- vsock_insert_connected(vsk);
sk->sk_state_change(sk);
break;
case VIRTIO_VSOCK_OP_INVALID:
@@ -1736,8 +1742,6 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
lock_sock_nested(child, SINGLE_DEPTH_NESTING);
- child->sk_state = TCP_ESTABLISHED;
-
vchild = vsock_sk(child);
vsock_addr_init(&vchild->local_addr, le64_to_cpu(hdr->dst_cid),
le32_to_cpu(hdr->dst_port));
@@ -1758,7 +1762,17 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
if (virtio_transport_space_update(child, skb))
child->sk_write_space(child);
- vsock_insert_connected(vchild);
+ /* An assign cannot see a socket that is not connected yet, and the
+ * check in vsock_assign_transport() above has since dropped
+ * vsock_register_mutex.
+ */
+ if (!vsock_maybe_set_connected(vchild)) {
+ release_sock(child);
+ virtio_transport_reset_no_sock(t, skb, sock_net(sk));
+ sock_put(child);
+ return -ENETUNREACH;
+ }
+
vsock_enqueue_accept(sk, child);
virtio_transport_send_response(vchild, skb);
--
2.53.0-Meta
next prev parent reply other threads:[~2026-09-02 23:01 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 23:00 [PATCH net-next 0/6] vsock: assign the guest vsock device to a network namespace Bobby Eshleman
2026-09-02 23:00 ` [PATCH net-next 1/6] vsock: constify the transport in vsock_for_each_connected_socket() Bobby Eshleman
2026-09-02 23:00 ` [PATCH net-next 2/6] vsock: add IOCTL_VM_SOCKETS_ASSIGN_G2H_NETNS Bobby Eshleman
2026-09-02 23:35 ` Randy Dunlap
2026-09-02 23:58 ` Bobby Eshleman
2026-09-02 23:00 ` Bobby Eshleman [this message]
2026-09-02 23:00 ` [PATCH net-next 4/6] selftests/vsock: add a helper to assign the g2h device to a netns Bobby Eshleman
2026-09-02 23:00 ` [PATCH net-next 5/6] selftests/vsock: test the guest vsock device network namespace Bobby Eshleman
2026-09-02 23:00 ` [PATCH net-next 6/6] selftests/vsock: test the assign ioctl privilege checks Bobby Eshleman
2026-09-04 8:55 ` [PATCH net-next 0/6] vsock: assign the guest vsock device to a network namespace Stefano Garzarella
2026-09-04 17:30 ` Bobby Eshleman
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=20260902-vsock-guest-ns-v1-3-9995383e9a8b@meta.com \
--to=bobbyeshleman@gmail.com \
--cc=bobbyeshleman@meta.com \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=eperezma@redhat.com \
--cc=horms@kernel.org \
--cc=jasowangio@gmail.com \
--cc=jlinbox@meta.com \
--cc=kuba@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rdunlap@infradead.org \
--cc=sargun@sargun.me \
--cc=sgarzare@redhat.com \
--cc=shuah@kernel.org \
--cc=skhan@linuxfoundation.org \
--cc=stefanha@redhat.com \
--cc=virtualization@lists.linux.dev \
--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