diff options
-rw-r--r-- | include/uapi/linux/vm_sockets.h | 26 | ||||
-rw-r--r-- | net/vmw_vsock/af_vsock.c | 21 | ||||
-rw-r--r-- | net/vmw_vsock/vsock_addr.c | 4 |
3 files changed, 47 insertions, 4 deletions
diff --git a/include/uapi/linux/vm_sockets.h b/include/uapi/linux/vm_sockets.h index fd0ed7221645..46918a1852d7 100644 --- a/include/uapi/linux/vm_sockets.h +++ b/include/uapi/linux/vm_sockets.h @@ -18,6 +18,7 @@ #define _UAPI_VM_SOCKETS_H #include <linux/socket.h> +#include <linux/types.h> /* Option name for STREAM socket buffer size. Use as the option name in * setsockopt(3) or getsockopt(3) to set or get an unsigned long long that @@ -114,6 +115,26 @@ #define VMADDR_CID_HOST 2 +/* The current default use case for the vsock channel is the following: + * local vsock communication between guest and host and nested VMs setup. + * In addition to this, implicitly, the vsock packets are forwarded to the host + * if no host->guest vsock transport is set. + * + * Set this flag value in the sockaddr_vm corresponding field if the vsock + * packets need to be always forwarded to the host. Using this behavior, + * vsock communication between sibling VMs can be setup. + * + * This way can explicitly distinguish between vsock channels created for + * different use cases, such as nested VMs (or local communication between + * guest and host) and sibling VMs. + * + * The flag can be set in the connect logic in the user space application flow. + * In the listen logic (from kernel space) the flag is set on the remote peer + * address. This happens for an incoming connection when it is routed from the + * host and comes from the guest (local CID and remote CID > VMADDR_CID_HOST). + */ +#define VMADDR_FLAG_TO_HOST 0x01 + /* Invalid vSockets version. */ #define VM_SOCKETS_INVALID_VERSION -1U @@ -148,10 +169,13 @@ struct sockaddr_vm { unsigned short svm_reserved1; unsigned int svm_port; unsigned int svm_cid; + __u8 svm_flags; unsigned char svm_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - sizeof(unsigned short) - - sizeof(unsigned int) - sizeof(unsigned int)]; + sizeof(unsigned int) - + sizeof(unsigned int) - + sizeof(__u8)]; }; #define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index d2834047c6db..b12d3a322242 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -421,7 +421,8 @@ 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 will use guest->host 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; */ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) @@ -429,8 +430,23 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) const struct vsock_transport *new_transport; struct sock *sk = sk_vsock(vsk); unsigned int remote_cid = vsk->remote_addr.svm_cid; + __u8 remote_flags; int ret; + /* If the packet is coming with the source and destination CIDs higher + * than VMADDR_CID_HOST, then a vsock channel where all the packets are + * forwarded to the host should be established. Then the host will + * need to forward the packets to the guest. + * + * The flag is set on the (listen) receive path (psk is not NULL). On + * the connect path the flag can be set by the user space application. + */ + if (psk && vsk->local_addr.svm_cid > VMADDR_CID_HOST && + vsk->remote_addr.svm_cid > VMADDR_CID_HOST) + vsk->remote_addr.svm_flags |= VMADDR_FLAG_TO_HOST; + + remote_flags = vsk->remote_addr.svm_flags; + switch (sk->sk_type) { case SOCK_DGRAM: new_transport = transport_dgram; @@ -438,7 +454,8 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) case SOCK_STREAM: 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 || !transport_h2g || + (remote_flags & VMADDR_FLAG_TO_HOST)) new_transport = transport_g2h; else new_transport = transport_h2g; diff --git a/net/vmw_vsock/vsock_addr.c b/net/vmw_vsock/vsock_addr.c index 909de26cb0e7..223b9660a759 100644 --- a/net/vmw_vsock/vsock_addr.c +++ b/net/vmw_vsock/vsock_addr.c @@ -22,13 +22,15 @@ EXPORT_SYMBOL_GPL(vsock_addr_init); int vsock_addr_validate(const struct sockaddr_vm *addr) { + __u8 svm_valid_flags = VMADDR_FLAG_TO_HOST; + if (!addr) return -EFAULT; if (addr->svm_family != AF_VSOCK) return -EAFNOSUPPORT; - if (addr->svm_zero[0] != 0) + if (addr->svm_flags & ~svm_valid_flags) return -EINVAL; return 0; |