kvm-guest-drivers-windows icon indicating copy to clipboard operation
kvm-guest-drivers-windows copied to clipboard

Sending message via viosock from Linux host to Windows guest fails

Open Youxu-Chen opened this issue 2 years ago • 1 comments

Describe the bug I try to establish a connection from a Linux host to a Windows guest via viosock. The viosock driver is installed in Windows guest successfully. The vsock server runs in Linux host and client runs in Windows guest. Messages can be sent normally from the client to the server. However, when I try to send a message from the server to the client, it fails and blocks in recv operation in the client side.

What's even more strange is that the first time a message is sent from the server to the client is normal, but the subsequent message is blocked, such as re-running the client program many times.

Demo code vsock server

/*
 * vsock_server.cc
 */
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/vm_sockets.h>
#include <string.h>
#include <stdio.h>

int main()
{
    int s = socket(AF_VSOCK, SOCK_STREAM, 0);

    struct sockaddr_vm addr;
    memset(&addr, 0, sizeof(struct sockaddr_vm));
    addr.svm_family = AF_VSOCK;
    addr.svm_port = 9999;
    addr.svm_cid = VMADDR_CID_HOST;

    bind(s, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm));

    listen(s, 0);

    struct sockaddr_vm peer_addr;
    socklen_t peer_addr_size = sizeof(struct sockaddr_vm);
    int peer_fd = accept(s, (struct sockaddr*)&peer_addr, &peer_addr_size);

    char buf[64];
    size_t msg_len;
    while ((msg_len = recv(peer_fd, &buf, 64, 0)) > 0) {
        printf("Received %lu bytes: %s\n", msg_len, buf);

        // send msg to client
        printf("Send msg to client...\n");
        char data[64]="Hi~";
        send(peer_fd, data, strlen(data), 0);
        printf("Send msg over!\n");
    }

    close(peer_fd);
    close(s);

    return 0;
}

vsock client

// vsock_client.cpp 
// Send a message to server and wait for a reply message
//

#include <tchar.h>
#include <Windows.h>
#include <WinSock2.h>
#include <iostream>

#include "vio_sockets.h"

#pragma comment(lib, "Ws2_32.lib")

BOOL Send( SOCKET sock, PCHAR Buffer, DWORD* BufferLen) {
    while (*BufferLen)
    {
        int len = send(sock, (char*)Buffer, *BufferLen, 0);
        if (len == SOCKET_ERROR)
        {
            _tprintf(_T("send failed: %d\n"), WSAGetLastError());
            return FALSE;
        }
        else if (!len)
        {
            _tprintf(_T("connection closed\n"));
            return TRUE;
        }
        else
        {
            _tprintf(_T("%d bytes sent\n"), len);
        }
        *BufferLen -= len;
        Buffer += len;
    }
    return TRUE;
}

BOOL Recv(SOCKET sock, PCHAR Buffer, DWORD* BufferLen) {
    int len = recv(sock, Buffer, *BufferLen, 0);

    if (len == SOCKET_ERROR)
    {
        _tprintf(_T("recv failed: %d\n"), WSAGetLastError());
        return FALSE;
    }
    else
    {
        _tprintf(_T("recv %d bytes\n"), len);
        if (!len)
        {
            _tprintf(_T("connection closed\n"));
        }
        else
        {
            *BufferLen = len;
        }
    }
    return TRUE;
}

int main()
{
    SOCKET sock = INVALID_SOCKET;
    WSADATA wsaData = { 0 };
    ADDRESS_FAMILY AF;

    int iRes = WSAStartup(MAKEWORD(2, 2), &wsaData);

    if (iRes != ERROR_SUCCESS)
    {
        return 1;
    }

    AF = ViosockGetAF();
    if (AF == AF_UNSPEC)
    {
        int error = GetLastError();
        char er[100];
        sprintf_s(er, "%d", error);
        MessageBox(NULL, er, "Tips", MB_OK);
        return 3;
    }

    sock = socket(AF, SOCK_STREAM, 0);
    SOCKADDR_VM addr{ 0 };
    addr.svm_cid = VMADDR_CID_HOST;
    addr.svm_port = 9999;
    addr.svm_family = AF;

    connect(sock, (struct sockaddr*)&addr, sizeof(addr));

    char buf[1024] = "Hello~";
    DWORD lenSend = strlen(buf);
    Send(sock, buf, &lenSend);

    printf("Wait msg from server...\n");
    char data[64]{};
    DWORD len=2;  // receive two bytes
    Recv(sock, data, &len);
    printf("Get msg from Server:%s\n", data);

    shutdown(sock, SD_BOTH);
    closesocket(sock);

    WSACleanup();
}

To Reproduce Steps to reproduce the behaviour:

  1. start vsock server in Linux host
  2. start vsock client in Windows guest
  3. observe the output of two side

The output of the client:

6 bytes sent
Wait msg from server...

The output of the server:

Received 6 bytes: Hello~
Send msg to client...
Send msg done!

Expected behavior Client can receive the reply message from server.

Host:

  • Disto: Ubuntu
  • Kernel version: 4.15.0-188-generic
  • QEMU version: qemu-x86_64 version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.40)
  • QEMU command line:
qemu-system-x86_64 -enable-kvm -name guest=win10-1650-1,debug-threads=on -S -object secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-10-win10-1650-1/master-key.aes -machine pc-i440fx-bionic,accel=kvm,usb=off,vmport=off,dump-guest-core=off -cpu host,hv_relaxed,hv_vapic,hv_spinlocks=0x1000,hv_vpindex,hv_runtime,hv_synic,hv_reset,hv_vendor_id=KVM Hv,kvm=off -m 16382 -realtime mlock=off -smp 8,sockets=1,cores=8,threads=1 -uuid 4fd9beb3-d3e4-44a3-926e-6c350c8a6e02 -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/domain-10-win10-1650-1/monitor.sock,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=delay -no-hpet -no-shutdown -global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -boot strict=on -device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,multifunction=off,addr=0xd -device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x5.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x5.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x5.0x2 -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x16 -drive file=/data2/vmImages/win10-1650-1.qcow2,format=qcow2,if=none,id=drive-ide0-0-0 -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 -drive if=none,id=drive-ide0-0-1,readonly=on -device ide-cd,bus=ide.0,unit=1,drive=drive-ide0-0-1,id=ide0-0-1 -netdev tap,fd=31,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:9d:08:3e,bus=pci.0,addr=0x8 -netdev tap,fd=33,id=hostnet1 -device rtl8139,netdev=hostnet1,id=net1,mac=52:54:00:b2:c7:49,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -chardev spicevmc,id=charchannel0,name=vdagent -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0 -spice port=5907,addr=127.0.0.1,disable-ticketing,image-compression=off,seamless-migration=on -vnc 0.0.0.0:8 -device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vram64_size_mb=0,vgamem_mb=16,max_outputs=1,bus=pci.0,addr=0x2 -device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 -chardev spicevmc,id=charredir0,name=usbredir -device usb-redir,chardev=charredir0,id=redir0,bus=usb.0,port=1 -chardev spicevmc,id=charredir1,name=usbredir -device usb-redir,chardev=charredir1,id=redir1,bus=usb.0,port=2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x17 -msg timestamp=on
  • libvirt version: 4.0.0
  • libvirt XML file:
<domain type='kvm' id='10'>
  <name>win10-1650-1</name>
  <uuid>4fd9beb3-d3e4-44a3-926e-6c350c8a6e02</uuid>
  <memory unit='KiB'>16775168</memory>
  <currentMemory unit='KiB'>16775168</currentMemory>
  <vcpu placement='static'>8</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-i440fx-bionic'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
    <hap state='on'/>
    <privnet/>
    <hyperv>
      <relaxed state='on'/>
      <vapic state='on'/>
      <spinlocks state='on' retries='4096'/>
      <vpindex state='on'/>
      <runtime state='on'/>
      <synic state='on'/>
      <reset state='on'/>
      <vendor_id state='on' value='KVM Hv'/>
    </hyperv>
    <kvm>
      <hidden state='on'/>
    </kvm>
    <vmport state='off'/>
  </features>
  <cpu mode='host-passthrough' check='none'>
    <topology sockets='1' cores='8' threads='1'/>
  </cpu>
  <clock offset='utc'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
    <emulator>/usr/bin/kvm-spice</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/data2/vmImages/win10-1650-1.qcow2'/>
      <backingStore/>
      <target dev='hda' bus='ide'/>
      <alias name='ide0-0-0'/>
      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <target dev='hdb' bus='ide'/>
      <readonly/>
      <alias name='ide0-0-1'/>
      <address type='drive' controller='0' bus='0' target='0' unit='1'/>
    </disk>
    <controller type='usb' index='0' model='ich9-ehci1'>
      <alias name='usb'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x7'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci1'>
      <alias name='usb'/>
      <master startport='0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0' multifunction='on'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci2'>
      <alias name='usb'/>
      <master startport='2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x1'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci3'>
      <alias name='usb'/>
      <master startport='4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <controller type='pci' index='1' model='pci-bridge'>
      <model name='pci-bridge'/>
      <target chassisNr='1'/>
      <alias name='pci.1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0' multifunction='off'/>
    </controller>
    <controller type='ide' index='0'>
      <alias name='ide'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <alias name='virtio-serial0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x16' function='0x0'/>
    </controller>
    <interface type='network'>
      <mac address='52:54:00:9d:08:3e'/>
      <source network='default' bridge='virbr0'/>
      <target dev='vnet8'/>
      <model type='rtl8139'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </interface>
    <interface type='bridge'>
      <mac address='52:54:00:b2:c7:49'/>
      <source bridge='br0'/>
      <target dev='vnet9'/>
      <model type='rtl8139'/>
      <alias name='net1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/7'/>
      <target type='isa-serial' port='0'>
        <model name='isa-serial'/>
      </target>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/7'>
      <source path='/dev/pts/7'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <channel type='spicevmc'>
      <target type='virtio' name='com.redhat.spice.0' state='disconnected'/>
      <alias name='channel0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <input type='mouse' bus='ps2'>
      <alias name='input0'/>
    </input>
    <input type='keyboard' bus='ps2'>
      <alias name='input1'/>
    </input>
    <graphics type='spice' port='5907' autoport='yes' listen='127.0.0.1'>
      <listen type='address' address='127.0.0.1'/>
      <image compression='off'/>
    </graphics>
    <graphics type='vnc' port='5908' autoport='yes' listen='0.0.0.0'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>
    <sound model='ich6'>
      <alias name='sound0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </sound>
    <video>
      <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <redirdev bus='usb' type='spicevmc'>
      <alias name='redir0'/>
      <address type='usb' bus='0' port='1'/>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
      <alias name='redir1'/>
      <address type='usb' bus='0' port='2'/>
    </redirdev>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x17' function='0x0'/>
    </memballoon>
  </devices>
</domain>

VM:

  • Windows version: Windows 10 21H2, 19044.1766
  • Windows vsock driver: viosock
  • Driver version or commit hash that was used to build the driver: 100.6.101.58000

Youxu-Chen avatar Jul 06 '22 02:07 Youxu-Chen

Hi,@irudakov77: Please help to confirm whether it is a problem with the viosock driver. If not, it may be a problem with my demo code.

Youxu-Chen avatar Jul 06 '22 03:07 Youxu-Chen

Hello, this problem also reproduces on my end with a similar test driver program. A client in the Windows guest can send messages to the Linux host. However after this tunnel is established the host cannot send anything in reply, recv(2) on the guest side will block indefinitely.

Additionally, if I run the server in the Windows guest, the Linux host acting as a client cannot establish a connection. I get errno 54, Connection reset by peer.

I'm running a Windows VM guest with:

Windows Server 21H2 (Build 20348.1249)
VirtIO socket driver: 7.16.3.100

Linux Host:

RHEL 8
Kernel 4.18.0-348.20.1.el8
QEMU emulator version 6.0.0 (qemu-kvm-6.0.0-33.el8)

Update: It seems my test driver had a few bugs. All is working on my side with this older version

tuxxi avatar Dec 07 '22 18:12 tuxxi

Hi @Youxu-Chen

After doing some more investigation, I believe the latest version in master has a commit that fixes this issue: https://github.com/virtio-win/kvm-guest-drivers-windows/pull/833

I was using an older version which did not have this specific problem, but the latest build available from https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/upstream-virtio/ has this exact problem.

Unfortunately I can't find a new build with the fix. You'll have to build the drivers yourself.

tuxxi avatar Dec 15 '22 18:12 tuxxi

Hello,

Unfortunately I can't find a new build with the fix. You'll have to build the drivers yourself.

No new build is available yet, however, we are working on it.

As of now, I can only make a test build of the viosock.sys` driver. This means you would need to turn on test signing and insert the test certificate into Trusted Root Certificate Authorities.

MartinDrab avatar Dec 24 '22 15:12 MartinDrab

@tuxxi @MartinDrab Thanks! I've tested the newer driver, the client and the host can send and receive messages successfully. It works!!!

Your help is much appreciated!!

Youxu-Chen avatar May 22 '23 07:05 Youxu-Chen

@Youxu-Chen

hello please help me!!,where can i download the driver? I am very very urgent ,please help me!!

RabitW avatar Oct 16 '23 11:10 RabitW

Should be in the latest version, https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.240-1/

YanVugenfirer avatar Oct 16 '23 12:10 YanVugenfirer

@YanVugenfirer but it not include viosock driver,i cann't find the avaiable driver package.

RabitW avatar Oct 16 '23 14:10 RabitW