* [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID
@ 2026-07-14 21:38 Hardik Garg
2026-07-16 15:21 ` Saurabh Singh Sengar
2026-07-16 17:03 ` Michael Kelley
0 siblings, 2 replies; 5+ messages in thread
From: Hardik Garg @ 2026-07-14 21:38 UTC (permalink / raw)
To: K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
linux-hyperv, linux-kernel
VMBus sends CHANNELMSG_INITIATE_CONTACT through a Hyper-V message
connection ID. Older protocol versions use VMBUS_MESSAGE_CONNECTION_ID,
while protocol version 5.0 and newer normally use
VMBUS_MESSAGE_CONNECTION_ID_4.
When the Linux VMBus driver runs at VTL2, the VMBus control plane may
be reached through a VMBus relay instead of the standard host endpoint.
In that setup the relay listens on the redirect message connection ID,
and an Initiate Contact message sent to the standard ID is not delivered
to the control plane.
The connection ID selects the Hyper-V message port used to reach the
VMBus control plane. If Linux uses the wrong port, the host does not
receive the Initiate Contact message.
For Linux running at VTL2 with VMBus protocol 5.0 or newer, try the
redirect connection ID first. In VTL2, the redirect connection ID is the
VMBus relay endpoint. If the relay is present, it accepts Initiate
Contact and completes the normal version-response handshake. Systems
without the relay reject the redirect ID synchronously with
HV_STATUS_INVALID_CONNECTION_ID, allowing fallback to
VMBUS_MESSAGE_CONNECTION_ID_4.
Return a distinct error for an invalid Initiate Contact connection ID so
this fallback does not mask other post-message failures or
protocol-version rejections. For older protocol versions, and for Linux
below VTL2, keep the existing connection ID selection.
Signed-off-by: Hardik Garg <hargar@linux.microsoft.com>
---
drivers/hv/connection.c | 76 ++++++++++++++++++++++++++++++++++++++++-------
drivers/hv/hyperv_vmbus.h | 2 ++
2 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 1fe3573ae52a4..eb871f87a819d 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -71,7 +71,19 @@ module_param(max_version, uint, S_IRUGO);
MODULE_PARM_DESC(max_version,
"Maximal VMBus protocol version which can be negotiated");
-int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
+/* Connection IDs to try for VTL2 VMBus protocol 5.0 and newer. */
+static const u32 connection_ids[] = {
+ VMBUS_MESSAGE_CONNECTION_ID_REDIRECT,
+ VMBUS_MESSAGE_CONNECTION_ID_4,
+};
+
+/*
+ * Send one CHANNELMSG_INITIATE_CONTACT attempt.
+ * The caller supplies the message connection ID and owns retry/fallback
+ * policy.
+ */
+static int vmbus_try_connection_id(struct vmbus_channel_msginfo *msginfo,
+ u32 version, u32 connection_id)
{
int ret = 0;
struct vmbus_channel_initiate_contact *msg;
@@ -87,7 +99,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
/*
* VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
- * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
+ * use connection_id for the Initiate Contact Message,
* and for subsequent messages, we must use the Message Connection ID
* field in the host-returned Version Response Message. And, with
* VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
@@ -99,7 +111,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
if (version >= VERSION_WIN10_V5) {
msg->msg_sint = VMBUS_MESSAGE_SINT;
msg->msg_vtl = ms_hyperv.vtl;
- vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
+ vmbus_connection.msg_conn_id = connection_id;
} else {
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
@@ -161,6 +173,51 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
return ret;
}
+/*
+ * Negotiate the given VMBus protocol version with the host.
+ * Protocol-specific connection ID policy is handled here so the single-try
+ * helper stays simple.
+ */
+int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
+{
+ int ret;
+ size_t j;
+
+ /*
+ * The redirect ID is not a speculative endpoint. If the VMBus relay is
+ * present, it accepts INITIATE_CONTACT and completes the normal version
+ * response. Systems without the relay reject the ID synchronously, so
+ * negotiation falls back to VMBUS_MESSAGE_CONNECTION_ID_4.
+ */
+ if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl >= 2) {
+ for (j = 0; j < ARRAY_SIZE(connection_ids); j++) {
+ ret = vmbus_try_connection_id(msginfo, version,
+ connection_ids[j]);
+ if (vmbus_connection.conn_state == CONNECTED)
+ return 0;
+
+ if (ret == -ETIMEDOUT)
+ return ret;
+
+ if (connection_ids[j] ==
+ VMBUS_MESSAGE_CONNECTION_ID_REDIRECT &&
+ ret == -ENXIO)
+ continue;
+
+ return ret;
+ }
+ return ret;
+ }
+
+ /*
+ * Non-redirect path. Protocol 5.0+ below VTL2 uses the standard
+ * v5 connection ID; pre-v5 ignores the supplied ID and uses the
+ * legacy connection ID.
+ */
+ return vmbus_try_connection_id(msginfo, version,
+ VMBUS_MESSAGE_CONNECTION_ID_4);
+}
+
/*
* vmbus_connect - Sends a connect request on the partition service connection
*/
@@ -455,17 +507,14 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
switch (ret) {
case HV_STATUS_INVALID_CONNECTION_ID:
/*
- * See vmbus_negotiate_version(): VMBus protocol 5.0
- * and higher require that we must use
- * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
- * Contact message, but on old hosts that only
- * support VMBus protocol 4.0 or lower, here we get
- * HV_STATUS_INVALID_CONNECTION_ID and we should
- * return an error immediately without retrying.
+ * Let negotiation distinguish an unusable
+ * endpoint from other failures.
+ *
+ * Other messages keep retry behavior.
*/
hdr = buffer;
if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
- return -EINVAL;
+ return -ENXIO;
/*
* We could get this if we send messages too
* frequently.
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 49a72a4f3f6a7..951bdebdc0526 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -109,6 +109,8 @@ struct hv_input_post_message {
enum {
VMBUS_MESSAGE_CONNECTION_ID = 1,
VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
+ /* VMBus relay port used for INITIATE_CONTACT probing. */
+ VMBUS_MESSAGE_CONNECTION_ID_REDIRECT = 0x800074,
VMBUS_MESSAGE_PORT_ID = 1,
VMBUS_EVENT_CONNECTION_ID = 2,
VMBUS_EVENT_PORT_ID = 2,
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID
2026-07-14 21:38 [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID Hardik Garg
@ 2026-07-16 15:21 ` Saurabh Singh Sengar
2026-07-16 20:53 ` Hardik Garg
2026-07-16 17:03 ` Michael Kelley
1 sibling, 1 reply; 5+ messages in thread
From: Saurabh Singh Sengar @ 2026-07-16 15:21 UTC (permalink / raw)
To: Hardik Garg
Cc: K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
linux-hyperv, linux-kernel
On Tue, Jul 14, 2026 at 09:38:38PM +0000, Hardik Garg wrote:
> VMBus sends CHANNELMSG_INITIATE_CONTACT through a Hyper-V message
> connection ID. Older protocol versions use VMBUS_MESSAGE_CONNECTION_ID,
> while protocol version 5.0 and newer normally use
> VMBUS_MESSAGE_CONNECTION_ID_4.
>
> When the Linux VMBus driver runs at VTL2, the VMBus control plane may
> be reached through a VMBus relay instead of the standard host endpoint.
> In that setup the relay listens on the redirect message connection ID,
> and an Initiate Contact message sent to the standard ID is not delivered
> to the control plane.
>
> The connection ID selects the Hyper-V message port used to reach the
> VMBus control plane. If Linux uses the wrong port, the host does not
> receive the Initiate Contact message.
>
> For Linux running at VTL2 with VMBus protocol 5.0 or newer, try the
> redirect connection ID first. In VTL2, the redirect connection ID is the
> VMBus relay endpoint. If the relay is present, it accepts Initiate
> Contact and completes the normal version-response handshake. Systems
> without the relay reject the redirect ID synchronously with
> HV_STATUS_INVALID_CONNECTION_ID, allowing fallback to
> VMBUS_MESSAGE_CONNECTION_ID_4.
>
> Return a distinct error for an invalid Initiate Contact connection ID so
> this fallback does not mask other post-message failures or
> protocol-version rejections. For older protocol versions, and for Linux
> below VTL2, keep the existing connection ID selection.
>
> Signed-off-by: Hardik Garg <hargar@linux.microsoft.com>
> ---
> drivers/hv/connection.c | 76 ++++++++++++++++++++++++++++++++++++++++-------
> drivers/hv/hyperv_vmbus.h | 2 ++
> 2 files changed, 67 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
> index 1fe3573ae52a4..eb871f87a819d 100644
> --- a/drivers/hv/connection.c
> +++ b/drivers/hv/connection.c
> @@ -71,7 +71,19 @@ module_param(max_version, uint, S_IRUGO);
> MODULE_PARM_DESC(max_version,
> "Maximal VMBus protocol version which can be negotiated");
>
> -int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> +/* Connection IDs to try for VTL2 VMBus protocol 5.0 and newer. */
> +static const u32 connection_ids[] = {
Do we want to name it vtl2_connection_ids ?
> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT,
> + VMBUS_MESSAGE_CONNECTION_ID_4,
> +};
> +
> +/*
> + * Send one CHANNELMSG_INITIATE_CONTACT attempt.
> + * The caller supplies the message connection ID and owns retry/fallback
> + * policy.
> + */
> +static int vmbus_try_connection_id(struct vmbus_channel_msginfo *msginfo,
> + u32 version, u32 connection_id)
> {
> int ret = 0;
> struct vmbus_channel_initiate_contact *msg;
> @@ -87,7 +99,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>
> /*
> * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
> - * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
> + * use connection_id for the Initiate Contact Message,
> * and for subsequent messages, we must use the Message Connection ID
> * field in the host-returned Version Response Message. And, with
> * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
> @@ -99,7 +111,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> if (version >= VERSION_WIN10_V5) {
> msg->msg_sint = VMBUS_MESSAGE_SINT;
> msg->msg_vtl = ms_hyperv.vtl;
> - vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
> + vmbus_connection.msg_conn_id = connection_id;
> } else {
> msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
> vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
> @@ -161,6 +173,51 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> return ret;
> }
>
> +/*
> + * Negotiate the given VMBus protocol version with the host.
> + * Protocol-specific connection ID policy is handled here so the single-try
> + * helper stays simple.
> + */
> +int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> +{
> + int ret;
> + size_t j;
> +
> + /*
> + * The redirect ID is not a speculative endpoint. If the VMBus relay is
> + * present, it accepts INITIATE_CONTACT and completes the normal version
> + * response. Systems without the relay reject the ID synchronously, so
> + * negotiation falls back to VMBUS_MESSAGE_CONNECTION_ID_4.
> + */
> + if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl >= 2) {
> + for (j = 0; j < ARRAY_SIZE(connection_ids); j++) {
> + ret = vmbus_try_connection_id(msginfo, version,
> + connection_ids[j]);
> + if (vmbus_connection.conn_state == CONNECTED)
> + return 0;
Do we need this ? ret is anyway 0 on success which we can return at the end ?
> +
> + if (ret == -ETIMEDOUT)
> + return ret;
> +
> + if (connection_ids[j] ==
> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT &&
> + ret == -ENXIO)
> + continue;
> +
> + return ret;
> + }
> + return ret;
Dead code
> + }
> +
> + /*
> + * Non-redirect path. Protocol 5.0+ below VTL2 uses the standard
> + * v5 connection ID; pre-v5 ignores the supplied ID and uses the
> + * legacy connection ID.
> + */
> + return vmbus_try_connection_id(msginfo, version,
> + VMBUS_MESSAGE_CONNECTION_ID_4);
> +}
> +
> /*
> * vmbus_connect - Sends a connect request on the partition service connection
> */
> @@ -455,17 +507,14 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
> switch (ret) {
> case HV_STATUS_INVALID_CONNECTION_ID:
> /*
> - * See vmbus_negotiate_version(): VMBus protocol 5.0
> - * and higher require that we must use
> - * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
> - * Contact message, but on old hosts that only
> - * support VMBus protocol 4.0 or lower, here we get
> - * HV_STATUS_INVALID_CONNECTION_ID and we should
> - * return an error immediately without retrying.
> + * Let negotiation distinguish an unusable
> + * endpoint from other failures.
> + *
> + * Other messages keep retry behavior.
> */
> hdr = buffer;
> if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
> - return -EINVAL;
> + return -ENXIO;
> /*
> * We could get this if we send messages too
> * frequently.
> diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
> index 49a72a4f3f6a7..951bdebdc0526 100644
> --- a/drivers/hv/hyperv_vmbus.h
> +++ b/drivers/hv/hyperv_vmbus.h
> @@ -109,6 +109,8 @@ struct hv_input_post_message {
> enum {
> VMBUS_MESSAGE_CONNECTION_ID = 1,
> VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
> + /* VMBus relay port used for INITIATE_CONTACT probing. */
Do we want to mention specific for VTL2 in comment ?
> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT = 0x800074,
> VMBUS_MESSAGE_PORT_ID = 1,
> VMBUS_EVENT_CONNECTION_ID = 2,
> VMBUS_EVENT_PORT_ID = 2,
> --
> 2.34.1
- Saurabh
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID
2026-07-14 21:38 [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID Hardik Garg
2026-07-16 15:21 ` Saurabh Singh Sengar
@ 2026-07-16 17:03 ` Michael Kelley
2026-07-16 22:04 ` Hardik Garg
1 sibling, 1 reply; 5+ messages in thread
From: Michael Kelley @ 2026-07-16 17:03 UTC (permalink / raw)
To: Hardik Garg, K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org
From: Hardik Garg <hargar@linux.microsoft.com> Sent: Tuesday, July 14, 2026 2:39 PM
>
> VMBus sends CHANNELMSG_INITIATE_CONTACT through a Hyper-V message
> connection ID. Older protocol versions use VMBUS_MESSAGE_CONNECTION_ID,
> while protocol version 5.0 and newer normally use
> VMBUS_MESSAGE_CONNECTION_ID_4.
>
> When the Linux VMBus driver runs at VTL2, the VMBus control plane may
> be reached through a VMBus relay instead of the standard host endpoint.
> In that setup the relay listens on the redirect message connection ID,
> and an Initiate Contact message sent to the standard ID is not delivered
> to the control plane.
>
> The connection ID selects the Hyper-V message port used to reach the
> VMBus control plane. If Linux uses the wrong port, the host does not
> receive the Initiate Contact message.
This is a judgment call, but to me the previous two paragraphs are
explaining VTL2 implementation details that aren't necessary for
understanding this patch. Yes, in earlier discussions I asked questions
about "why" all this funky behavior with connection IDs, but that's
just me as a former Microsoft insider. :-) Details about VMBus relays and
message ports are fairly obscure for people in the general Linux community.
It would be sufficient for the commit message to simply state that VTL2
may respond on either of two connection IDs. There's no separate indication
of which one will respond in a given VM, so it is necessary to try at runtime
to see which one works.
>
> For Linux running at VTL2 with VMBus protocol 5.0 or newer, try the
> redirect connection ID first. In VTL2, the redirect connection ID is the
> VMBus relay endpoint. If the relay is present, it accepts Initiate
> Contact and completes the normal version-response handshake. Systems
> without the relay reject the redirect ID synchronously with
> HV_STATUS_INVALID_CONNECTION_ID, allowing fallback to
> VMBUS_MESSAGE_CONNECTION_ID_4.
Is there a reason for trying the REDIRECT connection ID first? Or
is the ordering of trying arbitrary? If the REDIRECT connection
ID must be tried first, state that as a VTL2 requirement.
>
> Return a distinct error for an invalid Initiate Contact connection ID so
> this fallback does not mask other post-message failures or
> protocol-version rejections. For older protocol versions, and for Linux
> below VTL2, keep the existing connection ID selection.
>
> Signed-off-by: Hardik Garg <hargar@linux.microsoft.com>
> ---
> drivers/hv/connection.c | 76 ++++++++++++++++++++++++++++++++++++++++-------
> drivers/hv/hyperv_vmbus.h | 2 ++
> 2 files changed, 67 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
> index 1fe3573ae52a4..eb871f87a819d 100644
> --- a/drivers/hv/connection.c
> +++ b/drivers/hv/connection.c
> @@ -71,7 +71,19 @@ module_param(max_version, uint, S_IRUGO);
> MODULE_PARM_DESC(max_version,
> "Maximal VMBus protocol version which can be negotiated");
>
> -int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> +/* Connection IDs to try for VTL2 VMBus protocol 5.0 and newer. */
> +static const u32 connection_ids[] = {
> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT,
> + VMBUS_MESSAGE_CONNECTION_ID_4,
> +};
Using an array of connection IDs to iterate through matches the
design of how multiple VMBus protocols versions are tried. But with
only two entries in the array, this feels a bit over-engineered unless
there is reason to expect that more connection ID values are coming
in the reasonably near future. Absent an array, the code in the
vmbus_negotiate_version() could just hard code to test the redirect
connection ID first if running at VTL2, and if that fails with -ENXIO,
fall through to the normal case.
> +
> +/*
> + * Send one CHANNELMSG_INITIATE_CONTACT attempt.
> + * The caller supplies the message connection ID and owns retry/fallback
> + * policy.
> + */
> +static int vmbus_try_connection_id(struct vmbus_channel_msginfo *msginfo,
> + u32 version, u32 connection_id)
> {
> int ret = 0;
> struct vmbus_channel_initiate_contact *msg;
> @@ -87,7 +99,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>
> /*
> * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
> - * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
> + * use connection_id for the Initiate Contact Message,
This wording of this comment now feels a bit awkward. How about:
"For VMBus protocol 5.0 (VERSION_WIN10_V5) and higher, use the caller supplied
connection_id for the Initiate Contact Message so the caller can implement the
necessary retry scheme. For subsequent messages, use the Message Connection ID
field in the host-returned Version Response Message."
followed by the rest of the existing text.
> * and for subsequent messages, we must use the Message Connection ID
> * field in the host-returned Version Response Message. And, with
> * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
> @@ -99,7 +111,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> if (version >= VERSION_WIN10_V5) {
> msg->msg_sint = VMBUS_MESSAGE_SINT;
> msg->msg_vtl = ms_hyperv.vtl;
> - vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
> + vmbus_connection.msg_conn_id = connection_id;
> } else {
> msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
> vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
> @@ -161,6 +173,51 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> return ret;
> }
>
> +/*
> + * Negotiate the given VMBus protocol version with the host.
> + * Protocol-specific connection ID policy is handled here so the single-try
> + * helper stays simple.
> + */
> +int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
> +{
> + int ret;
> + size_t j;
> +
> + /*
> + * The redirect ID is not a speculative endpoint. If the VMBus relay is
What is a "speculative endpoint"? And per my comment above, I'd drop
discussion of VMBus relay, and just phrase things in terms of trying the
REDIRECT connection ID, and if that doesn't work, then try the normal one.
> + * present, it accepts INITIATE_CONTACT and completes the normal version
> + * response. Systems without the relay reject the ID synchronously, so
> + * negotiation falls back to VMBUS_MESSAGE_CONNECTION_ID_4.
> + */
> + if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl >= 2) {
> + for (j = 0; j < ARRAY_SIZE(connection_ids); j++) {
> + ret = vmbus_try_connection_id(msginfo, version,
> + connection_ids[j]);
> + if (vmbus_connection.conn_state == CONNECTED)
> + return 0;
> +
> + if (ret == -ETIMEDOUT)
> + return ret;
> +
> + if (connection_ids[j] ==
> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT &&
> + ret == -ENXIO)
> + continue;
> +
> + return ret;
> + }
> + return ret;
> + }
Per my earlier comment about not having an array of connection IDs, this
code could be as simple as:
if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl >=2) {
ret = vmbus_try_connection_id(msginfo, version,
VMBUS_MESSAGE_CONNECTION_ID_REDIRECT);
if (ret != -ENXIO)
return ret;
}
> +
> + /*
> + * Non-redirect path. Protocol 5.0+ below VTL2 uses the standard
> + * v5 connection ID; pre-v5 ignores the supplied ID and uses the
> + * legacy connection ID.
> + */
> + return vmbus_try_connection_id(msginfo, version,
> + VMBUS_MESSAGE_CONNECTION_ID_4);
> +}
> +
> /*
> * vmbus_connect - Sends a connect request on the partition service connection
> */
> @@ -455,17 +507,14 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
> switch (ret) {
> case HV_STATUS_INVALID_CONNECTION_ID:
> /*
> - * See vmbus_negotiate_version(): VMBus protocol 5.0
> - * and higher require that we must use
> - * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
> - * Contact message, but on old hosts that only
> - * support VMBus protocol 4.0 or lower, here we get
> - * HV_STATUS_INVALID_CONNECTION_ID and we should
> - * return an error immediately without retrying.
> + * Let negotiation distinguish an unusable
> + * endpoint from other failures.
> + *
> + * Other messages keep retry behavior.
> */
> hdr = buffer;
> if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
> - return -EINVAL;
> + return -ENXIO;
> /*
> * We could get this if we send messages too
> * frequently.
> diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
> index 49a72a4f3f6a7..951bdebdc0526 100644
> --- a/drivers/hv/hyperv_vmbus.h
> +++ b/drivers/hv/hyperv_vmbus.h
> @@ -109,6 +109,8 @@ struct hv_input_post_message {
> enum {
> VMBUS_MESSAGE_CONNECTION_ID = 1,
> VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
> + /* VMBus relay port used for INITIATE_CONTACT probing. */
> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT = 0x800074,
> VMBUS_MESSAGE_PORT_ID = 1,
> VMBUS_EVENT_CONNECTION_ID = 2,
> VMBUS_EVENT_PORT_ID = 2,
> --
> 2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID
2026-07-16 15:21 ` Saurabh Singh Sengar
@ 2026-07-16 20:53 ` Hardik Garg
0 siblings, 0 replies; 5+ messages in thread
From: Hardik Garg @ 2026-07-16 20:53 UTC (permalink / raw)
To: Saurabh Singh Sengar
Cc: K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
linux-hyperv, linux-kernel
On 7/16/2026 8:21 AM, Saurabh Singh Sengar wrote:
> On Tue, Jul 14, 2026 at 09:38:38PM +0000, Hardik Garg wrote:
>> VMBus sends CHANNELMSG_INITIATE_CONTACT through a Hyper-V message
>> connection ID. Older protocol versions use VMBUS_MESSAGE_CONNECTION_ID,
>> while protocol version 5.0 and newer normally use
>> VMBUS_MESSAGE_CONNECTION_ID_4.
>>
>> When the Linux VMBus driver runs at VTL2, the VMBus control plane may
>> be reached through a VMBus relay instead of the standard host endpoint.
>> In that setup the relay listens on the redirect message connection ID,
>> and an Initiate Contact message sent to the standard ID is not delivered
>> to the control plane.
>>
>> The connection ID selects the Hyper-V message port used to reach the
>> VMBus control plane. If Linux uses the wrong port, the host does not
>> receive the Initiate Contact message.
>>
>> For Linux running at VTL2 with VMBus protocol 5.0 or newer, try the
>> redirect connection ID first. In VTL2, the redirect connection ID is the
>> VMBus relay endpoint. If the relay is present, it accepts Initiate
>> Contact and completes the normal version-response handshake. Systems
>> without the relay reject the redirect ID synchronously with
>> HV_STATUS_INVALID_CONNECTION_ID, allowing fallback to
>> VMBUS_MESSAGE_CONNECTION_ID_4.
>>
>> Return a distinct error for an invalid Initiate Contact connection ID so
>> this fallback does not mask other post-message failures or
>> protocol-version rejections. For older protocol versions, and for Linux
>> below VTL2, keep the existing connection ID selection.
>>
>> Signed-off-by: Hardik Garg <hargar@linux.microsoft.com>
>> ---
>> drivers/hv/connection.c | 76 ++++++++++++++++++++++++++++++++++++++++-------
>> drivers/hv/hyperv_vmbus.h | 2 ++
>> 2 files changed, 67 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
>> index 1fe3573ae52a4..eb871f87a819d 100644
>> --- a/drivers/hv/connection.c
>> +++ b/drivers/hv/connection.c
>> @@ -71,7 +71,19 @@ module_param(max_version, uint, S_IRUGO);
>> MODULE_PARM_DESC(max_version,
>> "Maximal VMBus protocol version which can be negotiated");
>>
>> -int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> +/* Connection IDs to try for VTL2 VMBus protocol 5.0 and newer. */
>> +static const u32 connection_ids[] = {
> Do we want to name it vtl2_connection_ids ?
I will simplify this part in V2 and remove the array.
>> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT,
>> + VMBUS_MESSAGE_CONNECTION_ID_4,
>> +};
>> +
>> +/*
>> + * Send one CHANNELMSG_INITIATE_CONTACT attempt.
>> + * The caller supplies the message connection ID and owns retry/fallback
>> + * policy.
>> + */
>> +static int vmbus_try_connection_id(struct vmbus_channel_msginfo *msginfo,
>> + u32 version, u32 connection_id)
>> {
>> int ret = 0;
>> struct vmbus_channel_initiate_contact *msg;
>> @@ -87,7 +99,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>>
>> /*
>> * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
>> - * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
>> + * use connection_id for the Initiate Contact Message,
>> * and for subsequent messages, we must use the Message Connection ID
>> * field in the host-returned Version Response Message. And, with
>> * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
>> @@ -99,7 +111,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> if (version >= VERSION_WIN10_V5) {
>> msg->msg_sint = VMBUS_MESSAGE_SINT;
>> msg->msg_vtl = ms_hyperv.vtl;
>> - vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
>> + vmbus_connection.msg_conn_id = connection_id;
>> } else {
>> msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
>> vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
>> @@ -161,6 +173,51 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> return ret;
>> }
>>
>> +/*
>> + * Negotiate the given VMBus protocol version with the host.
>> + * Protocol-specific connection ID policy is handled here so the single-try
>> + * helper stays simple.
>> + */
>> +int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> +{
>> + int ret;
>> + size_t j;
>> +
>> + /*
>> + * The redirect ID is not a speculative endpoint. If the VMBus relay is
>> + * present, it accepts INITIATE_CONTACT and completes the normal version
>> + * response. Systems without the relay reject the ID synchronously, so
>> + * negotiation falls back to VMBUS_MESSAGE_CONNECTION_ID_4.
>> + */
>> + if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl >= 2) {
>> + for (j = 0; j < ARRAY_SIZE(connection_ids); j++) {
>> + ret = vmbus_try_connection_id(msginfo, version,
>> + connection_ids[j]);
>> + if (vmbus_connection.conn_state == CONNECTED)
>> + return 0;
> Do we need this ? ret is anyway 0 on success which we can return at the end ?
I will remove the redundant part.
>
>> +
>> + if (ret == -ETIMEDOUT)
>> + return ret;
>> +
>> + if (connection_ids[j] ==
>> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT &&
>> + ret == -ENXIO)
>> + continue;
>> +
>> + return ret;
>> + }
>> + return ret;
> Dead code
Will fix it in V2.
>
>> + }
>> +
>> + /*
>> + * Non-redirect path. Protocol 5.0+ below VTL2 uses the standard
>> + * v5 connection ID; pre-v5 ignores the supplied ID and uses the
>> + * legacy connection ID.
>> + */
>> + return vmbus_try_connection_id(msginfo, version,
>> + VMBUS_MESSAGE_CONNECTION_ID_4);
>> +}
>> +
>> /*
>> * vmbus_connect - Sends a connect request on the partition service connection
>> */
>> @@ -455,17 +507,14 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
>> switch (ret) {
>> case HV_STATUS_INVALID_CONNECTION_ID:
>> /*
>> - * See vmbus_negotiate_version(): VMBus protocol 5.0
>> - * and higher require that we must use
>> - * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
>> - * Contact message, but on old hosts that only
>> - * support VMBus protocol 4.0 or lower, here we get
>> - * HV_STATUS_INVALID_CONNECTION_ID and we should
>> - * return an error immediately without retrying.
>> + * Let negotiation distinguish an unusable
>> + * endpoint from other failures.
>> + *
>> + * Other messages keep retry behavior.
>> */
>> hdr = buffer;
>> if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
>> - return -EINVAL;
>> + return -ENXIO;
>> /*
>> * We could get this if we send messages too
>> * frequently.
>> diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
>> index 49a72a4f3f6a7..951bdebdc0526 100644
>> --- a/drivers/hv/hyperv_vmbus.h
>> +++ b/drivers/hv/hyperv_vmbus.h
>> @@ -109,6 +109,8 @@ struct hv_input_post_message {
>> enum {
>> VMBUS_MESSAGE_CONNECTION_ID = 1,
>> VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
>> + /* VMBus relay port used for INITIATE_CONTACT probing. */
> Do we want to mention specific for VTL2 in comment ?
Yes, that would be helpful. I will add it.
>
>> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT = 0x800074,
>> VMBUS_MESSAGE_PORT_ID = 1,
>> VMBUS_EVENT_CONNECTION_ID = 2,
>> VMBUS_EVENT_PORT_ID = 2,
>> --
>> 2.34.1
Thank you, Saurabh for the review.
Thanks,
Hardik
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID
2026-07-16 17:03 ` Michael Kelley
@ 2026-07-16 22:04 ` Hardik Garg
0 siblings, 0 replies; 5+ messages in thread
From: Hardik Garg @ 2026-07-16 22:04 UTC (permalink / raw)
To: Michael Kelley, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, linux-hyperv@vger.kernel.org,
linux-kernel@vger.kernel.org
On 7/16/2026 10:03 AM, Michael Kelley wrote:
> From: Hardik Garg <hargar@linux.microsoft.com> Sent: Tuesday, July 14, 2026 2:39 PM
>> VMBus sends CHANNELMSG_INITIATE_CONTACT through a Hyper-V message
>> connection ID. Older protocol versions use VMBUS_MESSAGE_CONNECTION_ID,
>> while protocol version 5.0 and newer normally use
>> VMBUS_MESSAGE_CONNECTION_ID_4.
>>
>> When the Linux VMBus driver runs at VTL2, the VMBus control plane may
>> be reached through a VMBus relay instead of the standard host endpoint.
>> In that setup the relay listens on the redirect message connection ID,
>> and an Initiate Contact message sent to the standard ID is not delivered
>> to the control plane.
>>
>> The connection ID selects the Hyper-V message port used to reach the
>> VMBus control plane. If Linux uses the wrong port, the host does not
>> receive the Initiate Contact message.
> This is a judgment call, but to me the previous two paragraphs are
> explaining VTL2 implementation details that aren't necessary for
> understanding this patch. Yes, in earlier discussions I asked questions
> about "why" all this funky behavior with connection IDs, but that's
> just me as a former Microsoft insider. :-) Details about VMBus relays and
> message ports are fairly obscure for people in the general Linux community.
> It would be sufficient for the commit message to simply state that VTL2
> may respond on either of two connection IDs. There's no separate indication
> of which one will respond in a given VM, so it is necessary to try at runtime
> to see which one works.
Good point, I will remove the extra details in v2.
>
>> For Linux running at VTL2 with VMBus protocol 5.0 or newer, try the
>> redirect connection ID first. In VTL2, the redirect connection ID is the
>> VMBus relay endpoint. If the relay is present, it accepts Initiate
>> Contact and completes the normal version-response handshake. Systems
>> without the relay reject the redirect ID synchronously with
>> HV_STATUS_INVALID_CONNECTION_ID, allowing fallback to
>> VMBUS_MESSAGE_CONNECTION_ID_4.
> Is there a reason for trying the REDIRECT connection ID first? Or
> is the ordering of trying arbitrary? If the REDIRECT connection
> ID must be tried first, state that as a VTL2 requirement.
I will add it as a VTL2 requirement. Redirect Id is used first as it
is the configured VMBus control-plane endpoint when VTL2 redirection
is enabled.
>
>> Return a distinct error for an invalid Initiate Contact connection ID so
>> this fallback does not mask other post-message failures or
>> protocol-version rejections. For older protocol versions, and for Linux
>> below VTL2, keep the existing connection ID selection.
>>
>> Signed-off-by: Hardik Garg <hargar@linux.microsoft.com>
>> ---
>> drivers/hv/connection.c | 76 ++++++++++++++++++++++++++++++++++++++++-------
>> drivers/hv/hyperv_vmbus.h | 2 ++
>> 2 files changed, 67 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
>> index 1fe3573ae52a4..eb871f87a819d 100644
>> --- a/drivers/hv/connection.c
>> +++ b/drivers/hv/connection.c
>> @@ -71,7 +71,19 @@ module_param(max_version, uint, S_IRUGO);
>> MODULE_PARM_DESC(max_version,
>> "Maximal VMBus protocol version which can be negotiated");
>>
>> -int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> +/* Connection IDs to try for VTL2 VMBus protocol 5.0 and newer. */
>> +static const u32 connection_ids[] = {
>> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT,
>> + VMBUS_MESSAGE_CONNECTION_ID_4,
>> +};
> Using an array of connection IDs to iterate through matches the
> design of how multiple VMBus protocols versions are tried. But with
> only two entries in the array, this feels a bit over-engineered unless
> there is reason to expect that more connection ID values are coming
> in the reasonably near future. Absent an array, the code in the
> vmbus_negotiate_version() could just hard code to test the redirect
> connection ID first if running at VTL2, and if that fails with -ENXIO,
> fall through to the normal case.
I used the array to accommodate new connection-ids in the future but I agree
that we don't need it currently. I will simplify it in v2.
>> +
>> +/*
>> + * Send one CHANNELMSG_INITIATE_CONTACT attempt.
>> + * The caller supplies the message connection ID and owns retry/fallback
>> + * policy.
>> + */
>> +static int vmbus_try_connection_id(struct vmbus_channel_msginfo *msginfo,
>> + u32 version, u32 connection_id)
>> {
>> int ret = 0;
>> struct vmbus_channel_initiate_contact *msg;
>> @@ -87,7 +99,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>>
>> /*
>> * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
>> - * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
>> + * use connection_id for the Initiate Contact Message,
> This wording of this comment now feels a bit awkward. How about:
>
> "For VMBus protocol 5.0 (VERSION_WIN10_V5) and higher, use the caller supplied
> connection_id for the Initiate Contact Message so the caller can implement the
> necessary retry scheme. For subsequent messages, use the Message Connection ID
> field in the host-returned Version Response Message."
>
> followed by the rest of the existing text.
Will update the comment in V2
>
>
>> * and for subsequent messages, we must use the Message Connection ID
>> * field in the host-returned Version Response Message. And, with
>> * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
>> @@ -99,7 +111,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> if (version >= VERSION_WIN10_V5) {
>> msg->msg_sint = VMBUS_MESSAGE_SINT;
>> msg->msg_vtl = ms_hyperv.vtl;
>> - vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
>> + vmbus_connection.msg_conn_id = connection_id;
>> } else {
>> msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
>> vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
>> @@ -161,6 +173,51 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> return ret;
>> }
>>
>> +/*
>> + * Negotiate the given VMBus protocol version with the host.
>> + * Protocol-specific connection ID policy is handled here so the single-try
>> + * helper stays simple.
>> + */
>> +int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
>> +{
>> + int ret;
>> + size_t j;
>> +
>> + /*
>> + * The redirect ID is not a speculative endpoint. If the VMBus relay is
> What is a "speculative endpoint"? And per my comment above, I'd drop
> discussion of VMBus relay, and just phrase things in terms of trying the
> REDIRECT connection ID, and if that doesn't work, then try the normal one.
I will simplify the comment in V2
>
>
>> + * present, it accepts INITIATE_CONTACT and completes the normal version
>> + * response. Systems without the relay reject the ID synchronously, so
>> + * negotiation falls back to VMBUS_MESSAGE_CONNECTION_ID_4.
>> + */
>> + if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl >= 2) {
>> + for (j = 0; j < ARRAY_SIZE(connection_ids); j++) {
>> + ret = vmbus_try_connection_id(msginfo, version,
>> + connection_ids[j]);
>> + if (vmbus_connection.conn_state == CONNECTED)
>> + return 0;
>> +
>> + if (ret == -ETIMEDOUT)
>> + return ret;
>> +
>> + if (connection_ids[j] ==
>> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT &&
>> + ret == -ENXIO)
>> + continue;
>> +
>> + return ret;
>> + }
>> + return ret;
>> + }
> Per my earlier comment about not having an array of connection IDs, this
> code could be as simple as:
>
> if (version >= VERSION_WIN10_V5 && ms_hyperv.vtl >=2) {
> ret = vmbus_try_connection_id(msginfo, version,
> VMBUS_MESSAGE_CONNECTION_ID_REDIRECT);
> if (ret != -ENXIO)
> return ret;
> }
I will update this part as per the earlier feedback.
>> +
>> + /*
>> + * Non-redirect path. Protocol 5.0+ below VTL2 uses the standard
>> + * v5 connection ID; pre-v5 ignores the supplied ID and uses the
>> + * legacy connection ID.
>> + */
>> + return vmbus_try_connection_id(msginfo, version,
>> + VMBUS_MESSAGE_CONNECTION_ID_4);
>> +}
>> +
>> /*
>> * vmbus_connect - Sends a connect request on the partition service connection
>> */
>> @@ -455,17 +507,14 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
>> switch (ret) {
>> case HV_STATUS_INVALID_CONNECTION_ID:
>> /*
>> - * See vmbus_negotiate_version(): VMBus protocol 5.0
>> - * and higher require that we must use
>> - * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
>> - * Contact message, but on old hosts that only
>> - * support VMBus protocol 4.0 or lower, here we get
>> - * HV_STATUS_INVALID_CONNECTION_ID and we should
>> - * return an error immediately without retrying.
>> + * Let negotiation distinguish an unusable
>> + * endpoint from other failures.
>> + *
>> + * Other messages keep retry behavior.
>> */
>> hdr = buffer;
>> if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
>> - return -EINVAL;
>> + return -ENXIO;
>> /*
>> * We could get this if we send messages too
>> * frequently.
>> diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
>> index 49a72a4f3f6a7..951bdebdc0526 100644
>> --- a/drivers/hv/hyperv_vmbus.h
>> +++ b/drivers/hv/hyperv_vmbus.h
>> @@ -109,6 +109,8 @@ struct hv_input_post_message {
>> enum {
>> VMBUS_MESSAGE_CONNECTION_ID = 1,
>> VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
>> + /* VMBus relay port used for INITIATE_CONTACT probing. */
>> + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT = 0x800074,
>> VMBUS_MESSAGE_PORT_ID = 1,
>> VMBUS_EVENT_CONNECTION_ID = 2,
>> VMBUS_EVENT_PORT_ID = 2,
>> --
>> 2.34.1
Thank you for the review, Michael.
Thanks,
Hardik
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-16 22:04 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-14 21:38 [PATCH] Drivers: hv: vmbus: add VTL2 redirect connection ID Hardik Garg
2026-07-16 15:21 ` Saurabh Singh Sengar
2026-07-16 20:53 ` Hardik Garg
2026-07-16 17:03 ` Michael Kelley
2026-07-16 22:04 ` Hardik Garg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox