linux/net/vmw_vsock/hyperv_transport.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Hyper-V transport for vsock
 *
 * Hyper-V Sockets supplies a byte-stream based communication mechanism
 * between the host and the VM. This driver implements the necessary
 * support in the VM by introducing the new vsock transport.
 *
 * Copyright (c) 2017, Microsoft Corporation.
 */
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/hyperv.h>
#include <net/sock.h>
#include <net/af_vsock.h>
#include <asm/hyperv-tlfs.h>

/* Older (VMBUS version 'VERSION_WIN10' or before) Windows hosts have some
 * stricter requirements on the hv_sock ring buffer size of six 4K pages.
 * hyperv-tlfs defines HV_HYP_PAGE_SIZE as 4K. Newer hosts don't have this
 * limitation; but, keep the defaults the same for compat.
 */
#define RINGBUFFER_HVS_RCV_SIZE
#define RINGBUFFER_HVS_SND_SIZE
#define RINGBUFFER_HVS_MAX_SIZE

/* The MTU is 16KB per the host side's design */
#define HVS_MTU_SIZE

/* How long to wait for graceful shutdown of a connection */
#define HVS_CLOSE_TIMEOUT

struct vmpipe_proto_header {};

/* For recv, we use the VMBus in-place packet iterator APIs to directly copy
 * data from the ringbuffer into the userspace buffer.
 */
struct hvs_recv_buf {};

/* We can send up to HVS_MTU_SIZE bytes of payload to the host, but let's use
 * a smaller size, i.e. HVS_SEND_BUF_SIZE, to maximize concurrency between the
 * guest and the host processing as one VMBUS packet is the smallest processing
 * unit.
 *
 * Note: the buffer can be eliminated in the future when we add new VMBus
 * ringbuffer APIs that allow us to directly copy data from userspace buffer
 * to VMBus ringbuffer.
 */
#define HVS_SEND_BUF_SIZE

struct hvs_send_buf {};

#define HVS_HEADER_LEN

/* See 'prev_indices' in hv_ringbuffer_read(), hv_ringbuffer_write(), and
 * __hv_pkt_iter_next().
 */
#define VMBUS_PKT_TRAILER_SIZE

#define HVS_PKT_LEN(payload_len)

/* Upper bound on the size of a VMbus packet for hv_sock */
#define HVS_MAX_PKT_SIZE

hvs_service_id;

/* Per-socket state (accessed via vsk->trans) */
struct hvsock {};

/* In the VM, we support Hyper-V Sockets with AF_VSOCK, and the endpoint is
 * <cid, port> (see struct sockaddr_vm). Note: cid is not really used here:
 * when we write apps to connect to the host, we can only use VMADDR_CID_ANY
 * or VMADDR_CID_HOST (both are equivalent) as the remote cid, and when we
 * write apps to bind() & listen() in the VM, we can only use VMADDR_CID_ANY
 * as the local cid.
 *
 * On the host, Hyper-V Sockets are supported by Winsock AF_HYPERV:
 * https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-
 * guide/make-integration-service, and the endpoint is <VmID, ServiceId> with
 * the below sockaddr:
 *
 * struct SOCKADDR_HV
 * {
 *    ADDRESS_FAMILY Family;
 *    USHORT Reserved;
 *    GUID VmId;
 *    GUID ServiceId;
 * };
 * Note: VmID is not used by Linux VM and actually it isn't transmitted via
 * VMBus, because here it's obvious the host and the VM can easily identify
 * each other. Though the VmID is useful on the host, especially in the case
 * of Windows container, Linux VM doesn't need it at all.
 *
 * To make use of the AF_VSOCK infrastructure in Linux VM, we have to limit
 * the available GUID space of SOCKADDR_HV so that we can create a mapping
 * between AF_VSOCK port and SOCKADDR_HV Service GUID. The rule of writing
 * Hyper-V Sockets apps on the host and in Linux VM is:
 *
 ****************************************************************************
 * The only valid Service GUIDs, from the perspectives of both the host and *
 * Linux VM, that can be connected by the other end, must conform to this   *
 * format: <port>-facb-11e6-bd58-64006a7986d3.                              *
 ****************************************************************************
 *
 * When we write apps on the host to connect(), the GUID ServiceID is used.
 * When we write apps in Linux VM to connect(), we only need to specify the
 * port and the driver will form the GUID and use that to request the host.
 *
 */

/* 00000000-facb-11e6-bd58-64006a7986d3 */
static const guid_t srv_id_template =;

static bool hvs_check_transport(struct vsock_sock *vsk);

static bool is_valid_srv_id(const guid_t *id)
{}

static unsigned int get_port_by_srv_id(const guid_t *svr_id)
{}

static void hvs_addr_init(struct sockaddr_vm *addr, const guid_t *svr_id)
{}

static void hvs_set_channel_pending_send_size(struct vmbus_channel *chan)
{}

static bool hvs_channel_readable(struct vmbus_channel *chan)
{}

static int hvs_channel_readable_payload(struct vmbus_channel *chan)
{}

static size_t hvs_channel_writable_bytes(struct vmbus_channel *chan)
{}

static int __hvs_send_data(struct vmbus_channel *chan,
			   struct vmpipe_proto_header *hdr,
			   size_t to_write)
{}

static int hvs_send_data(struct vmbus_channel *chan,
			 struct hvs_send_buf *send_buf, size_t to_write)
{}

static void hvs_channel_cb(void *ctx)
{}

static void hvs_do_close_lock_held(struct vsock_sock *vsk,
				   bool cancel_timeout)
{}

static void hvs_close_connection(struct vmbus_channel *chan)
{}

static void hvs_open_connection(struct vmbus_channel *chan)
{}

static u32 hvs_get_local_cid(void)
{}

static int hvs_sock_init(struct vsock_sock *vsk, struct vsock_sock *psk)
{}

static int hvs_connect(struct vsock_sock *vsk)
{}

static void hvs_shutdown_lock_held(struct hvsock *hvs, int mode)
{}

static int hvs_shutdown(struct vsock_sock *vsk, int mode)
{}

static void hvs_close_timeout(struct work_struct *work)
{}

/* Returns true, if it is safe to remove socket; false otherwise */
static bool hvs_close_lock_held(struct vsock_sock *vsk)
{}

static void hvs_release(struct vsock_sock *vsk)
{}

static void hvs_destruct(struct vsock_sock *vsk)
{}

static int hvs_dgram_bind(struct vsock_sock *vsk, struct sockaddr_vm *addr)
{}

static int hvs_dgram_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
			     size_t len, int flags)
{}

static int hvs_dgram_enqueue(struct vsock_sock *vsk,
			     struct sockaddr_vm *remote, struct msghdr *msg,
			     size_t dgram_len)
{}

static bool hvs_dgram_allow(u32 cid, u32 port)
{}

static int hvs_update_recv_data(struct hvsock *hvs)
{}

static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
				  size_t len, int flags)
{}

static ssize_t hvs_stream_enqueue(struct vsock_sock *vsk, struct msghdr *msg,
				  size_t len)
{}

static s64 hvs_stream_has_data(struct vsock_sock *vsk)
{}

static s64 hvs_stream_has_space(struct vsock_sock *vsk)
{}

static u64 hvs_stream_rcvhiwat(struct vsock_sock *vsk)
{}

static bool hvs_stream_is_active(struct vsock_sock *vsk)
{}

static bool hvs_stream_allow(u32 cid, u32 port)
{}

static
int hvs_notify_poll_in(struct vsock_sock *vsk, size_t target, bool *readable)
{}

static
int hvs_notify_poll_out(struct vsock_sock *vsk, size_t target, bool *writable)
{}

static
int hvs_notify_recv_init(struct vsock_sock *vsk, size_t target,
			 struct vsock_transport_recv_notify_data *d)
{}

static
int hvs_notify_recv_pre_block(struct vsock_sock *vsk, size_t target,
			      struct vsock_transport_recv_notify_data *d)
{}

static
int hvs_notify_recv_pre_dequeue(struct vsock_sock *vsk, size_t target,
				struct vsock_transport_recv_notify_data *d)
{}

static
int hvs_notify_recv_post_dequeue(struct vsock_sock *vsk, size_t target,
				 ssize_t copied, bool data_read,
				 struct vsock_transport_recv_notify_data *d)
{}

static
int hvs_notify_send_init(struct vsock_sock *vsk,
			 struct vsock_transport_send_notify_data *d)
{}

static
int hvs_notify_send_pre_block(struct vsock_sock *vsk,
			      struct vsock_transport_send_notify_data *d)
{}

static
int hvs_notify_send_pre_enqueue(struct vsock_sock *vsk,
				struct vsock_transport_send_notify_data *d)
{}

static
int hvs_notify_send_post_enqueue(struct vsock_sock *vsk, ssize_t written,
				 struct vsock_transport_send_notify_data *d)
{}

static
int hvs_notify_set_rcvlowat(struct vsock_sock *vsk, int val)
{}

static struct vsock_transport hvs_transport =;

static bool hvs_check_transport(struct vsock_sock *vsk)
{}

static int hvs_probe(struct hv_device *hdev,
		     const struct hv_vmbus_device_id *dev_id)
{}

static void hvs_remove(struct hv_device *hdev)
{}

/* hv_sock connections can not persist across hibernation, and all the hv_sock
 * channels are forced to be rescinded before hibernation: see
 * vmbus_bus_suspend(). Here the dummy hvs_suspend() and hvs_resume()
 * are only needed because hibernation requires that every vmbus device's
 * driver should have a .suspend and .resume callback: see vmbus_suspend().
 */
static int hvs_suspend(struct hv_device *hv_dev)
{}

static int hvs_resume(struct hv_device *dev)
{}

/* This isn't really used. See vmbus_match() and vmbus_probe() */
static const struct hv_vmbus_device_id id_table[] =;

static struct hv_driver hvs_drv =;

static int __init hvs_init(void)
{}

static void __exit hvs_exit(void)
{}

module_init();
module_exit(hvs_exit);

MODULE_DESCRIPTION();
MODULE_VERSION();
MODULE_LICENSE();
MODULE_ALIAS_NETPROTO();