[RFC,11/13] vsock: add 'transport_hg' to handle g2h\h2g transports
diff mbox series

Message ID 20190927112703.17745-12-sgarzare@redhat.com
State RFC
Delegated to: David Miller
Headers show
Series
  • vsock: add multi-transports support
Related show

Commit Message

Stefano Garzarella Sept. 27, 2019, 11:27 a.m. UTC
VMCI transport provides both g2h and h2g behaviors in a single
transport.
We are able to set (or not) the g2h behavior, detecting if we
are in a VMware guest (or not), but the h2g feature is always set.
This prevents to load other h2g transports while we are in a
VMware guest.

This patch adds a new 'transport_hg' to handle this case, reducing
the priority of transports that provide both g2h and h2g
behaviors. A transport that has g2h and h2g features, can be
bypassed by a transport that has only the h2g feature.

Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
 net/vmw_vsock/af_vsock.c | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

Comments

Stefano Garzarella Oct. 9, 2019, 9:44 a.m. UTC | #1
On Fri, Sep 27, 2019 at 01:27:01PM +0200, Stefano Garzarella wrote:
> VMCI transport provides both g2h and h2g behaviors in a single
> transport.
> We are able to set (or not) the g2h behavior, detecting if we
> are in a VMware guest (or not), but the h2g feature is always set.
> This prevents to load other h2g transports while we are in a
> VMware guest.
> 
> This patch adds a new 'transport_hg' to handle this case, reducing
> the priority of transports that provide both g2h and h2g
> behaviors. A transport that has g2h and h2g features, can be
> bypassed by a transport that has only the h2g feature.
> 

Since I'm enabling the VSOCK_TRANSPORT_F_G2H in the vmci_transport only
when we run in a VMware guest, this patch doesn't work well if a KVM (or
HyperV) guest application create an AF_VSOCK socket and no transports are
loaded, because in this case the vmci_transport is loaded
(MODULE_ALIAS_NETPROTO(PF_VSOCK)) and it is registered as transport_h2g.

At this point, if we want to run a nested VM using vhost_transport, we
can't load it.

So, I can leave VSOCK_TRANSPORT_F_G2H always set in the vmci_transport
and this should fix this issue.
Or maybe I need to change how the registering works, e.g. handling a list
of transport registered, setting priority or using the last registered
transport.

Any suggestion?

Thanks,
Stefano
Stefan Hajnoczi Oct. 9, 2019, 1:16 p.m. UTC | #2
On Fri, Sep 27, 2019 at 01:27:01PM +0200, Stefano Garzarella wrote:
> VMCI transport provides both g2h and h2g behaviors in a single
> transport.
> We are able to set (or not) the g2h behavior, detecting if we
> are in a VMware guest (or not), but the h2g feature is always set.
> This prevents to load other h2g transports while we are in a
> VMware guest.

In the vhost_vsock.ko case we only register the h2g transport when
userspace has loaded the module (by opening /dev/vhost-vsock).

VMCI has something kind of similar: /dev/vmci and the
vmci_host_active_users counter.  Maybe we can use this instead of
introducing the transport_hg concept?
Stefano Garzarella Oct. 10, 2019, 1:04 p.m. UTC | #3
On Wed, Oct 09, 2019 at 02:16:43PM +0100, Stefan Hajnoczi wrote:
> On Fri, Sep 27, 2019 at 01:27:01PM +0200, Stefano Garzarella wrote:
> > VMCI transport provides both g2h and h2g behaviors in a single
> > transport.
> > We are able to set (or not) the g2h behavior, detecting if we
> > are in a VMware guest (or not), but the h2g feature is always set.
> > This prevents to load other h2g transports while we are in a
> > VMware guest.
> 
> In the vhost_vsock.ko case we only register the h2g transport when
> userspace has loaded the module (by opening /dev/vhost-vsock).
> 
> VMCI has something kind of similar: /dev/vmci and the
> vmci_host_active_users counter.  Maybe we can use this instead of
> introducing the transport_hg concept?

Yes, maybe we can register the host in the vmci_host_do_init_context().

I also don't like a lot the transport_hg concept, so I'll try to found
an alternative.

Thanks,
Stefano

Patch
diff mbox series

diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index c52203fe52c4..c5f46b8242ce 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -134,6 +134,8 @@  static 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 both host->guest and guest->host communication */
+static const struct vsock_transport *transport_hg;
 /* Transport used for DGRAM communication */
 static const struct vsock_transport *transport_dgram;
 static DEFINE_MUTEX(vsock_register_mutex);
@@ -402,10 +404,13 @@  int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
 		vsk->transport = transport_dgram;
 		break;
 	case SOCK_STREAM:
-		if (vsk->remote_addr.svm_cid > VMADDR_CID_HOST)
+		if (vsk->remote_addr.svm_cid > VMADDR_CID_HOST) {
 			vsk->transport = transport_h2g;
-		else
+			if (!vsk->transport)
+				vsk->transport = transport_hg;
+		} else {
 			vsk->transport = transport_g2h;
+		}
 		break;
 	default:
 		return -ESOCKTNOSUPPORT;
@@ -423,7 +428,7 @@  static bool vsock_find_cid(unsigned int cid)
 	if (transport_g2h && cid == transport_g2h->get_local_cid())
 		return true;
 
-	if (transport_h2g && cid == VMADDR_CID_HOST)
+	if ((transport_h2g || transport_hg) && cid == VMADDR_CID_HOST)
 		return true;
 
 	return false;
@@ -1997,6 +2002,8 @@  static long vsock_dev_do_ioctl(struct file *filp,
 			cid = transport_g2h->get_local_cid();
 		else if (transport_h2g)
 			cid = transport_h2g->get_local_cid();
+		else if (transport_hg)
+			cid = transport_hg->get_local_cid();
 
 		if (put_user(cid, p) != 0)
 			retval = -EFAULT;
@@ -2093,13 +2100,14 @@  EXPORT_SYMBOL_GPL(vsock_core_get_transport);
 
 int vsock_core_register(const struct vsock_transport *t)
 {
-	const struct vsock_transport *t_h2g, *t_g2h, *t_dgram;
+	const struct vsock_transport *t_h2g, *t_hg, *t_g2h, *t_dgram;
 	int err = mutex_lock_interruptible(&vsock_register_mutex);
 
 	if (err)
 		return err;
 
 	t_h2g = transport_h2g;
+	t_hg = transport_hg;
 	t_g2h = transport_g2h;
 	t_dgram = transport_dgram;
 
@@ -2107,7 +2115,14 @@  int vsock_core_register(const struct vsock_transport *t)
 	 * same transport. We are able to set the G2H feature only if we are
 	 * in a VMware guest, but we are not able to do the same for the host.
 	 */
-	if (t->features & VSOCK_TRANSPORT_F_H2G) {
+	if ((t->features & VSOCK_TRANSPORT_F_H2G) &&
+	    (t->features & VSOCK_TRANSPORT_F_G2H)) {
+		if (t_hg) {
+			err = -EBUSY;
+			goto err_busy;
+		}
+		t_hg = t;
+	} else if (t->features & VSOCK_TRANSPORT_F_H2G) {
 		if (t_h2g) {
 			err = -EBUSY;
 			goto err_busy;
@@ -2132,6 +2147,7 @@  int vsock_core_register(const struct vsock_transport *t)
 	}
 
 	transport_h2g = t_h2g;
+	transport_hg = t_hg;
 	transport_g2h = t_g2h;
 	transport_dgram = t_dgram;
 
@@ -2151,6 +2167,9 @@  void vsock_core_unregister(const struct vsock_transport *t)
 	if (transport_h2g == t)
 		transport_h2g = NULL;
 
+	if (transport_hg == t)
+		transport_hg = NULL;
+
 	if (transport_g2h == t)
 		transport_g2h = NULL;