Host port forward with qemu through libvirt in user-mode networking

forwardinglibvirtnetworkingport-forwardingqemu

I'm having trouble editing my libvirt's host-xml to make qemu forward TCP connections to the guest. This questions linked to a blog post which recommended adding -redir to the Qemu command line. But that stopped working as of recently.

error: internal error: qemu unexpectedly closed the monitor:
qemu-system-x86_64: -redir tcp:5564::3389: The -redir option is
deprecated. Please use '-netdev user,hostfwd=…' instead.

That, however, doesn't work out of the box, i.e. I get the open port on the host, but it doesn't go through to the client.

I edited my XML like this:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  .
  .
  .
  </devices>
  <qemu:commandline>
    <qemu:arg value='-net'/>
    <qemu:arg value='user,hostfwd=tcp::22222-:22,hostfwd=tcp::8000-:8000'/>
  </qemu:commandline>
</domain>

My test was to then run nc -l -p 8000 on the client and telnet localhost 8000 on the host. Telnet indicates an opened TCP connection but the client doesn't receive anything.

I guess it's because libvirt already included a -net user,... option and somehow my newly defined option isn't processed properly. ps aux | grep qemu shows this:

qemu-system-x86_64 -enable-kvm -name guest=myguestsname,debug-threads=on -S -object secret,id=masterKey0,format=raw,file=~/.config/libvirt/qemu/lib/domain-28-myguestsname/master-key.aes -machine pc-i440fx-artful,accel=kvm,usb=off,vmport=off,dump-guest-core=off -cpu Skylake-Client -m 1024 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 713287321 -no-user-config -nodefaults -chardev socket,id=charmonitor,path=~/.config/libvirt/qemu/lib/domain-28-myguestsname/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 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=0x6 -drive file=~/.local/share/libvirt/images/myguestsname.img,format=qcow2,if=none,id=drive-virtio-disk0 -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x7,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -drive file=Cloud-Init-ISO/master-init.iso,format=raw,if=none,id=drive-ide0-0-0,readonly=on -device ide-cd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 -fsdev local,security_model=mapped,id=fsdev-fs0,path=~/guestfs -device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=guestsfs,bus=pci.0,addr=0x9 -netdev user,id=hostnet0 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:aa:aa:0a,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 -device usb-tablet,id=input0,bus=usb.0,port=1 -spice port=5900,addr=127.0.0.1,disable-ticketing,image-compression=off,seamless-migration=on -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=2 -chardev spicevmc,id=charredir1,name=usbredir -device usb-redir,chardev=charredir1,id=redir1,bus=usb.0,port=3 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x8 -net user,hostfwd=tcp::22222-:22,hostfwd=tcp::8000-:8000 -msg timestamp=on

We can see -netdev user,id=hostnet0. I tried to use the same name in my custom command line, but that fails:

error: internal error: process exited while connecting to monitor:
qemu-system-x86_64: -chardev
pty,id=charserial0: char device redirected to /dev/pts/23 (label
charserial0)

qemu-system-x86_64: -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:aa:aa:0a,bus=pci.0,addr=0x3: Property 'virtio-net-device.netdev' can't take value 'hostnet0', it's
in use

For non user-mode networking setups, several questions exist already.
But I need to work with user-mode networking.

How would I properly forward ports using libvirt with qemu and user-mode networking?

The documentation is not really helpful, here, because it does not say how to sort of override already existing device definitions.

Best Answer

the missing part from your configuration is described here: https://www.linux-kvm.org/page/Networking. You have to add another netdev with new address like so:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
.
.
.
 </devices>
 <qemu:commandline>
   <qemu:arg value='-netdev'/>
   <qemu:arg value='user,id=mynet.0,net=10.0.10.0/24,hostfwd=tcp::22222-:22,hostfwd=tcp::8000-:8000'/>
   <qemu:arg value='-device'/>
   <qemu:arg value='e1000,netdev=mynet.0'/>
 </qemu:commandline>
</domain>