Esta pagina se ve mejor con JavaScript habilitado

Qemu en FreeBSD

 ·  🎃 kr0m

Es sabido que una de las fortalezas de FreeBSD es su sistema de virtualización mediante jails , pero hay ocasiones en las que necesitaremos instalar algún sistema no-FreeBSD, ya sea un Windoz o Linux.

En estos casos se suele optar por algún gestor basado en Bhyve , pero si el equipo es muy viejo(en mi caso: IntelCore2Duo P9500/2.53GHz) y no dispone de las extensiones de virtualización necesarias a nivel de CPU, Bhyve no podrá funcionar, la única opción que nos queda es Qemu.

Qemu es mucho mas lento ya que se emula un procesador completo sin utilizar ninguna ayuda hardware, según el uso que le vayamos a dar esto resultará viable o no.
Pero no todo es malo, Qemu permite delegar solo un puerto USB a una máquina virtual, cosa que con BHyve no era posible si no era delegando una tarjeta PCI entera .


Instalación Qemu:

Instalamos el software:

pkg install qemu

Vamos a hacer las pruebas con una Debian, así que nos bajamos la ISO:

wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.1.0-amd64-netinst.iso

Creamos el disco duro:

mkdir qemu-vms
qemu-img create -f qcow2 /root/qemu-vms/debian13.img 50G

Arrancamos la máquina virtual desde el CD-ROM:

qemu-system-x86_64 -m 2048 -hda /root/qemu-vms/debian13.img -cdrom debian-13.1.0-amd64-netinst.iso -boot d -vnc :0 -vga std

Si tenemos el tráfico filtrado en el servidor padre mediante PF , debemos añadir una ACL para tener acceso al VNC/SSH de la máquina virtual y añadir reglas adicionales en caso de proporcionar otros servicios en la máquina virtual:

vi /etc/pf.conf
# VNC Qemu installation:
pass in proto tcp from 192.168.XX.XX to any port 5900
# SSH Qemu:
pass in proto tcp to 192.168.XX.XX port 2222

Accedemos al VNC:

vncviewer 192.168.YY.YY:5900

En mi caso resulta necesario delegar un puerto USB a la máquina virtual, así que identificamos el puerto en cuestión:

usbconfig
ugen1.3: <RTL2838 DVB-T Realtek Semiconductor Corp.> at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (500mA)

Desvinculamos el USB del SO antes de pasárselo a la máquian virtual:

usbconfig -u 1 -a 3 detach_kernel_driver

Le pasamos el puerto USB, por defecto Qemu utiliza SLIRP(NAT red interna), así que debemos redirigir los puertos que nos interesen:

qemu-system-x86_64 \
  -accel tcg,thread=multi \
  -cpu max \
  -smp 2 \
  -m 2048 \
  -drive file=/root/qemu-vms/debian13.img,if=virtio,cache=writeback \
  -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8073-:8073 \
  -device virtio-net,netdev=net0 \
  -device qemu-xhci,id=xhci \
  -device usb-host,hostbus=1,hostaddr=3 \
  -vnc :0 -vga std \
  -daemonize

Accedemos a la máquina virtual via SSH:

ssh kr0m@192.168.YY.YY -p2222

Donde podemos comprobar que efectivamente se le ha delegado el puerto USB:

lsusb
Bus 001 Device 002: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T

Para parar la máquina virtual no basta con un halt, he tenido que utilizar systemctl poweroff.

Cada vez que creemos una máquina virtual nueva debemos tomar la precaución de no pisar el puerto SSH ni el VNC, si lo hacemos veremos estos mensajes:

qemu-system-x86_64: -netdev user,id=net0,hostfwd=tcp::2222-:22: Could not set up host forwarding rule 'tcp::2222-:22'
qemu-system-x86_64: -vnc :0: Failed to find an available port: Address already in use

Un ejemplo cambiado al siguiente puerto sería:

-netdev user,id=net0,hostfwd=tcp::2223-:22 --> ssh kr0m@192.168.YY.YY -p2223
-vnc :1 -vga std  --> vncviewer 192.168.YY.YY:5901

Si se trata de una máquina virtual que vamos a utilizar de forma asidua, la mejor manera de gestionarla es mediante un script de RC:

vi /usr/local/etc/rc.d/qemuDebian
#!/bin/sh
#
# PROVIDE: qemuDebian
# REQUIRE: DAEMON
# KEYWORD: shutdown

. /etc/rc.subr

name=qemuDebian
rcvar=qemuDebian_enable

command="/usr/local/bin/qemu-system-x86_64"
command_args="\
  -accel tcg,thread=multi \
  -cpu max \
  -smp 2 \
  -m 2048 \
  -drive file=/root/qemu-vms/debian13.img,if=virtio,cache=writeback \
  -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8073-:8073 \
  -device virtio-net,netdev=net0 \
  -device qemu-xhci,id=xhci \
  -device usb-host,hostbus=1,hostaddr=3 \
  -vnc :0 -vga std"
start_cmd="${name}_start"
stop_cmd="${name}_stop"
status_cmd="${name}_status"
pidfile="/var/run/${name}.pid"

qemuDebian_start(){
    echo "Starting service: ${name}."
    /usr/sbin/daemon -c -f -p ${pidfile} ${command} ${command_args}
}

qemuDebian_stop(){
    if [ -f ${pidfile} ]; then
        echo "Stopping service: ${name}"
        kill -s TERM $(cat ${pidfile})
        sleep 3
    else
        echo "It appears ${name} is not running."
    fi
}

qemuDebian_status(){
    if [ -f ${pidfile} ]; then
        echo "${name} running with PID: $(cat ${pidfile})"
    else
        echo "It appears ${name} is not running."
    fi
}

load_rc_config $name
run_rc_command "$1"

NOTA: Como ahora lanzamos Qemu desde daemon, no hace falta el parámetro -daemonize

Asignamos permisos:

chmod 555 /usr/local/etc/rc.d/qemuDebian

Habilitamos el servicio y lo arrancamos:

sysrc qemuDebian_enable="YES"
service qemuDebian start

Comprobamos que haya arrancado:

service qemuDebian status

Trucos:

Podemos ver un htop de las máquina Qemu pero debemos tener en cuenta que si se lanzan nuevas máquinas tendremos que relanzar el comando para que refresque la lista:

htop -p $(pgrep qemu-system | tr '\n' ',' | sed 's/,$//')

Podemos consultar información de un disco de este modo:

qemu-img info /root/qemu-vms/debian13.img
image: /root/qemu-vms/debian13.img
file format: qcow2
virtual size: 50 GiB (53687091200 bytes)
disk size: 2.21 GiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false
Child node '/file':
    filename: /root/qemu-vms/debian13.img
    protocol type: file
    file length: 4.77 GiB (5116657664 bytes)
    disk size: 2.21 GiB

Como podemos ver la información cuadra:

du -h /root/qemu-vms/debian13.img
2.2G	/root/qemu-vms/debian13.img

Cada vez que creemos una máquina virtual nueva debemos tomar la precaución de no pisar el puerto SSH ni el VNC, si lo hacemos veremos estos mensajes:

qemu-system-x86_64: -netdev user,id=net0,hostfwd=tcp::2222-:22: Could not set up host forwarding rule 'tcp::2222-:22'
qemu-system-x86_64: -vnc :0: Failed to find an available port: Address already in use

Un ejemplo cambiado al siguiente puerto sería:

-netdev user,id=net0,hostfwd=tcp::2223-:22 --> ssh kr0m@192.168.YY.YY -p2223
-vnc :1 -vga std  --> vncviewer 192.168.YY.YY:5901