* [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-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-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 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