Datos personales

jueves, 11 de diciembre de 2008

VirtualBox. Puertos USB en Ubuntu.

En este artículo vamos a ver cómo se activan los puertos USB para que puedan ser utilizados en las máquinas virtuales que hemos creado con VirtualBox. El sistema anfitrión es Linux Ubuntu 8.04.

VirtualBox tiene dos versiones: OSE (Open Source Edition) y PUEL (Personal Use and Evaluation License). Yo siempre he trabajado con las versiones OSE. La versión PUEL no es libre y, por lo tanto, no es gratuita, aunque existe una versión de evaluación para uso personal (PUEL). En la página oficial de VirtualBox indica cómo se descarga esta versión junto con la clave de utilización del producto.

Cuando se me ha planteado la necesidad de utilizar los puertos USB en mis máquinas virtuales, he encontrado información en internet sobre la forma de realizar la configuración, pero , ¡sorpresa: los puertos USB sólo se pueden utilizar con la versión PUEL!.

Como, en esto de la informática, además de tener tiempo, hay que ser algo intrépido, he decidido probar la información que he encontrado en internet en la versión OSE, para no tener que cambiar a la versión PUEL, y ha ocurrido algo que no suele ser muy habitual: ¡HA FUNCIONADO!. La prueba la he realizado con las versiones 2.0.6 (que es la última en el momento de escribir este artículo) y 1.6.0 y con máquinas virtuales con Linux Ubuntu 8.04 y Windows XP en ambas versiones y todo ha funcionado correctamente. Los dispositivos que he utilizado han sido una impresora, un disco duro externo y un pendrive.

He aquí las acciones a realizar para utilizar los puertos USB en VirtualBox OSE (se supone que en la versión PUEL también funcionaría, pero no le probado; mi intrepidez tiene un límite).

En primer lugar, tenemos que editar el archivo /etc/init.d/mountdevsubfs.sh y buscar el siguiente párrafo:

#
# Magic to make /proc/bus/usb work
#
# mkdir -p /dev/bus/usb/.usbfs
# domount usbfs "" /dev/bus/usb/.usbfs -obusmode=0700,devmode=0600,listmode=0644
# ln -s .usbfs/devices /dev/bus/usb/devices
# mount --rbind /dev/bus/usb /proc/bus/usb

El archivo /etc/init.d/mountdevsubfs.sh es un script que monta dispositivos especiales en nuestro sistema de archivos. El sistema lo trata como un servicio (está en el directorio /etc/init.d).

Tenemos que modificar el bloque anterior del archivo /etc/init.d/mountdevsubfs.sh quitando los comentarios a las líneas ejecutables, quedando como sigue:

#
# Magic to make /proc/bus/usb work
#
mkdir -p /dev/bus/usb/.usbfs
domount usbfs "" /dev/bus/usb/.usbfs -obusmode=0700,devmode=0600,listmode=0644
ln -s .usbfs/devices /dev/bus/usb/devices
mount --rbind /dev/bus/usb /proc/bus/usb

A continuación, tenemos que editar el archivo /etc/udev/rules.d/40-permissions.rules y buscar el siguiente párrafo:

# USB serial converters
SUBSYSTEM=="usb_device", GOTO="usb_serial_start"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", GOTO="usb_serial_start"
GOTO="usb_serial_end"
LABEL="usb_serial_start"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
MODE="0660", GROUP="dialout"
LABEL="usb_serial_end"

En el archivo /etc/udev/rules.d/40-permissions.rules se definen los usuarios y los grupos que pueden acceder a los dispositivos del sistema, debiendo añadir el grupo vboxusers (este grupo es el que utiliza VirtualBox) para que podamos acceder desde nuestras máquinas virtuales a los puertos USB. La orden se añade en el bloque anterior, en la línea ATTRS{idVendor}, quedando como sigue (he escrito en negrita la modificación añadida) :

# USB serial converters
SUBSYSTEM=="usb_device", GOTO="usb_serial_start"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", GOTO="usb_serial_start"
GOTO="usb_serial_end"
LABEL="usb_serial_start"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
,GROUP="vboxusers",MODE="0660", GROUP="dialout"
LABEL="usb_serial_end"

Seguidamente, hay que editar el archivo /etc/udev/rules.d/40-basic-permissions.rules y buscar el siguiente párrafo:

# USB devices (usbfs replacement)
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
SUBSYSTEM=="usb_device", MODE="0664"

En el archivo /etc/udev/rules.d/40-basic-permissions.rules se definen los tipos de accesos a los dispositivos del sistema que se permiten a los usuarios y grupos. Nosotros tenemos que modificar los permisos para que todos los usuarios puedan leer y escribir en los puertos USB, quedando el párrafo como sigue (he escrito en negrita la modificación realizada) :

# USB devices (usbfs replacement)
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0666"
SUBSYSTEM=="usb_device", MODE="0666"

Para que esta configuración tenga efecto hay que reiniciar el equipo (probablemente habrá servicios que, reiniciándose, activen esta configuración, pero los desconozco).

Una vez reiniciado el sistema, hay que configurar cada una de las máquinas virtuales para que activen los puertos USB al iniciarse. Para ello, hay que acceder, desde VirtualBox, a la configuración de la máquina virtual y abrir la opción USB, accediendo a una nueva ventana en la que hay que habilitar los puertos USB y pulsar sobre el icono para Agregar Filtro desde Dispositivo. Ver la Figura 1.

Figura 1

Accedemos a la ventana de la Figura 2.

Figura 2

En esta ventana se muestran los dispositivos USB conectados en ese momento al sistema. Si no se muestra ningún dispositivo es porque no están conectados. Tenemos que seleccionar los dispositivos que queramos e irán insertándose en la ventana de la Figura 1, debiendo repetir esta operación para cada uno de los dispositivos. Una vez finalizada esta acción, se visualizará una ventana parecida a la de la Figura 3.

Figura 3

En este ejemplo se han agregado una impresora, un disco duro externo y un pendrive. Esto quiere decir que los dispositivos, desde este momento, se pueden utilizar en esta máquina virtual. Cada vez que se conecte uno de estos dispositivos y la máquina virtual esté ejecutándose, el dispositivo será accesible desde la máquina virtual, pero no desde el equipo anfitrión. Si no queremos utilizar uno de estos dispositivos desde la máquina virtual, tenemos que desactivar su casilla correspondiente en la ventana de la Figura 3 y, posteriormente, ejecutar la máquina. De esta forma, el dispositivo será accesible sólo desde el equipo anfitrión.

martes, 2 de diciembre de 2008

VirtualBox. Configurar la red en Linux.

Cuando se instala una máquina virtual con VirtualBox, la tarjeta de red se configura en modo NAT, que no dispone de funciones avanzadas de red y, por lo tanto, las prestaciones de la interfaz de red son muy limitadas. Con este modo, VirtualBox utiliza su propio enrutador y DHCP, permitiendo salir a internet desde la máquina virtual, pero impidiendo, entre otras acciones, comunicarnos con el equipo anfitrión o, si tenemos dos máquinas virtuales en el mismo equipo anfitrión, comunicarse entre ellas. Para conocer las limitaciones que tenemos con esta configuración, se puede consultar la ayuda de VirtualBox: Virtual networking -> Networking Address Translation -> NAT limitations.

En este artículo se va a configurar la tarjeta de red de la máquina virtual para que no tengamos estas limitaciones y, por ejemplo, podamos conectarnos con el equipo anfitrión y comunicar dos o más máquinas virtuales creadas en el mismo equipo anfitrión.

La correcta configuración consiste en crear un bridge (puente) para unir las interfaces de red del equipo anfitrión y de la máquina o máquinas virtuales. Vamos a ello (recuerdo que el equipo anfitrión tiene instalado una distribución de Linux; en mi caso, Linux Ubuntu 8.04).

Todas las operaciones las vamos a realizar desde un terminal. Al ser tareas administrativas, vamos a ejecutar la orden sudo su y escribir nuestra contraseña para no tener que escribir sudo delante de cada orden.

La configuración inicial de la tarjeta de red del equipo anfitrión podemos consultarla en el archivo /etc/network/interfaces:

root@elnuevo:/home/coralio# cat /etc/network/interfaces

auto lo

iface lo inet loopback

auto eth0

iface eth0 inet dhcp


Las líneas referentes a la interfaz eth0 pueden no estar incluidas en este archivo si estamos utilizando el modo itinerante.

Si ejecutamos la orden ifconfig, se visualizará la información sobre las tarjetas de red:

root@elnuevo:/home/coralio# ifconfig

eth0 Link encap:Ethernet direcciónHW 00:1d:72:07:df:f0

inet dirección:192.168.1.33 Difusión:192.168.1.255 Máscara:255.255.255.0

dirección inet6: fe80::21d:72ff:fe07:dff0/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:9 errors:0 dropped:0 overruns:0 frame:0

TX packets:40 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:1000

RX bytes:1254 (1.2 KB) TX bytes:6028 (5.8 KB)

Interrupción:16


lo Link encap:Bucle local

inet dirección:127.0.0.1 Máscara:255.0.0.0

dirección inet6: ::1/128 Alcance:Anfitrión

ARRIBA LOOPBACK CORRIENDO MTU:16436 Métrica:1

RX packets:1252 errors:0 dropped:0 overruns:0 frame:0

TX packets:1252 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:0

RX bytes:62600 (61.1 KB) TX bytes:62600 (61.1 KB)


Para crear y utilizar el bridge hay que descargar e instalar el paquete bridge-utils:

root@elnuevo:/home/coralio# apt-get install bridge-utils

Este software nos instala las utilidades necesarias para administrar el bridge. Si ejecutamos la orden brctl se muestran algunas de estas utilidades:

root@elnuevo:/home/coralio# brctl

La siguiente acción a realizar es crear el bridge:

root@elnuevo:/home/coralio# brctl addbr br0


A continuación, hay que crear la interfaz virtual que se utilizará desde la máquina virtual (esta acción se realiza con la orden VBoxAddIF que proporciona VirtualBox; se puede consultar la ayuda de VirtualBox para más información sobre estas órdenes):

root@elnuevo:/home/coralio# VBoxAddIF vbox0 coralio br0

VirtualBox host networking interface creation utility, version 1.6.0

(C) 2005-2007 Sun Microsystems, Inc.

All rights reserved.


Creating the permanent host networking interface "vbox0" for user coralio.


La orden VBoxAddIF crea la interfaz virtual vbox0 que utilizará la máquina virtual, asigna permisos al usuario coralio para utilizar la interfaz (esto significa que esta interfaz no podrá utilizarla otro usuario) y la enlaza con el bridge br0 creado previamente.

Si queremos utilizar otra máquina virtual en el mismo equipo anfitrión, hay que crear otra interfaz virtual para esta nueva máquina, ya que cada máquina virtual debe disponer de su propia interfaz virtual. En la siguiente orden se crea la interfaz virtual vbox1 para que sea utilizada por el usuario coralio y se añade al bridge br0 creado anteriormente:

root@elnuevo:/home/coralio# VBoxAddIF vbox1 coralio br0

VirtualBox host networking interface creation utility, version 1.6.0

(C) 2005-2007 Sun Microsystems, Inc.

All rights reserved.


Creating the permanent host networking interface "vbox1" for user coralio.


Podemos ver la configuración del bridge con las dos interfaces virtuales que se le han añadido ejecutando la siguiente orden:

root@elnuevo:/home/coralio# brctl show

bridge name bridge id STP enabled interfaces

br0 8000.00ff09719902 no vbox0

vbox1


La siguiente acción es modificar el archivo /etc/network/interfaces para que la configuración del bridge y de las tarjetas de red real y virtuales tenga efecto cuando se encienda el sistema o se reinicie el servicio networking. El contenido de este archivo sería el siguiente:

root@elnuevo:/home/coralio# gedit /etc/network/interfaces

auto lo

iface lo inet loopback


auto eth0

iface eth0 inet dhcp


auto br0

iface br0 inet dhcp

bridge_ports eth0 vbox0 vbox1


El bloque relativo al bridge br0 obtiene la dirección IP para br0 del servicio DHCP e indica que toda la información que entre o salga por las interfaces eth0, vbox0 y vbox1 se dirigirá al bridge.

Para que todo funcione hay que levantar el bridge y reiniciar el servicio networking:

root@elnuevo:/home/coralio# ifconfig br0 up


root@elnuevo:/home/coralio# /etc/init.d/networking restart


Con esta configuración todo debería funcionar correctamente, pero no es así. El problema es que, tanto la tarjeta de red real como las virtuales, funcionan de forma intermitente: unas veces sí y otras veces no. Si ejecutamos la orden ifconfig veremos la configuración que hemos realizado:

root@elnuevo:/home/coralio# ifconfig

br0 Link encap:Ethernet direcciónHW 00:ff:09:71:99:02

inet dirección:192.168.1.33 Difusión:192.168.1.255 Máscara:255.255.255.0

dirección inet6: fe80::2ff:9ff:fe71:9902/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:25 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:0

RX bytes:0 (0.0 B) TX bytes:5534 (5.4 KB)


eth0 Link encap:Ethernet direcciónHW 00:1d:72:07:df:f0

inet dirección:192.168.1.33 Difusión:192.168.1.255 Máscara:255.255.255.0

dirección inet6: fe80::21d:72ff:fe07:dff0/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:15 errors:0 dropped:0 overruns:0 frame:0

TX packets:43 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:1000

RX bytes:1826 (1.7 KB) TX bytes:6379 (6.2 KB)

Interrupción:16

lo Link encap:Bucle local

inet dirección:127.0.0.1 Máscara:255.0.0.0

dirección inet6: ::1/128 Alcance:Anfitrión

ARRIBA LOOPBACK CORRIENDO MTU:16436 Métrica:1

RX packets:1270 errors:0 dropped:0 overruns:0 frame:0

TX packets:1270 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:0

RX bytes:63500 (62.0 KB) TX bytes:63500 (62.0 KB)


vbox0 Link encap:Ethernet direcciónHW 00:ff:09:71:99:02

dirección inet6: fe80::2ff:9ff:fe71:9902/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:25 overruns:0 carrier:0

colisiones:0 txqueuelen:500

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)


vbox1 Link encap:Ethernet direcciónHW 00:ff:ca:ec:c2:8c

dirección inet6: fe80::2ff:caff:feec:c28c/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:25 overruns:0 carrier:0

colisiones:0 txqueuelen:500

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)


Después de probar varias configuraciones, he llegado a la conclusión de que el problema surge porque la tarjeta de red real (eth0) y el bridge (br0) comparten la misma dirección IP (podemos verlas en la salida anterior de la orden ifconfig).

La solución que he encontrado consiste en levantar la interfaz eth0 sin asignarle ninguna dirección IP y que sólo el bridge br0 obtenga la dirección IP. El nuevo contenido del archivo /etc/network/interfaces sería el siguiente:

root@elnuevo:/home/coralio# gedit /etc/network/interfaces

auto lo

iface lo inet loopback


auto eth0

iface eth0 inet manual


auto br0

iface br0 inet dhcp

bridge_ports eth0 vbox0 vbox1


El único cambio que he realizado en este archivo es cambiar la línea iface eth0 inet dhcp por la línea iface eth0 inet manual, consiguiendo así que la interfaz eth0 se levante pero no se le asigne ninguna dirección IP. Esta configuración la he estado probando con dos máquinas virtuales (con arranque dual en Windows y Linux las dos) más el equipo anfitrión y ha funcionado de forma estable durante bastantes días.

Para que esta configuración tenga efecto, hay que reiniciar el servicio networking:

root@elnuevo:/home/coralio# /etc/init.d/networking restart


Si ejecutamos la orden ifconfig veremos que todas las interfaces están levantadas pero la interfaz eth0 no tiene dirección IP:

root@elnuevo:/home/coralio# ifconfig

br0 Link encap:Ethernet direcciónHW 00:1d:72:07:df:f0

inet dirección:192.168.1.33 Difusión:192.168.1.255 Máscara:255.255.255.0

dirección inet6: fe80::21d:72ff:fe07:dff0/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:8 errors:0 dropped:0 overruns:0 frame:0

TX packets:27 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:0

RX bytes:1042 (1.0 KB) TX bytes:4565 (4.4 KB)


eth0 Link encap:Ethernet direcciónHW 00:1d:72:07:df:f0

dirección inet6: fe80::21d:72ff:fe07:dff0/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:8 errors:0 dropped:0 overruns:0 frame:0

TX packets:27 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:1000

RX bytes:1186 (1.1 KB) TX bytes:4697 (4.5 KB)

Interrupción:16


lo Link encap:Bucle local

inet dirección:127.0.0.1 Máscara:255.0.0.0

dirección inet6: ::1/128 Alcance:Anfitrión

ARRIBA LOOPBACK CORRIENDO MTU:16436 Métrica:1

RX packets:1288 errors:0 dropped:0 overruns:0 frame:0

TX packets:1288 errors:0 dropped:0 overruns:0 carrier:0

colisiones:0 txqueuelen:0

RX bytes:64400 (62.8 KB) TX bytes:64400 (62.8 KB)


vbox0 Link encap:Ethernet direcciónHW 00:ff:09:71:99:02

dirección inet6: fe80::2ff:9ff:fe71:9902/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:55 overruns:0 carrier:0

colisiones:0 txqueuelen:500

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)


vbox1 Link encap:Ethernet direcciónHW 00:ff:ca:ec:c2:8c

dirección inet6: fe80::2ff:caff:feec:c28c/64 Alcance:Vínculo

ARRIBA DIFUSIÓN CORRIENDO MULTICAST MTU:1500 Métrica:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:33 overruns:0 carrier:0

colisiones:0 txqueuelen:500

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)


Si vemos la configuración del bridge, obtendremos la siguiente salida:

root@elnuevo:/home/coralio# brctl show

bridge name bridge id STP enabled interfaces

br0 8000.001d7207dff0 no eth0

vbox0

vbox1


Esta salida indica que las interfaces eth0, vbox0 y vbox1 están utilizando el puente br0.

Seguidamente, hay que asignar permisos a los usuarios sobre el directorio /dev/net/tun que utiliza el sistema para gestionar las interfaces virtuales.

root@elnuevo:/home/coralio# chmod 0666 /dev/net/tun


Para finalizar, hay que indicar en la configuración de la red de la máquina virtual (desde VirtualBox) que se va a utilizar la configuración de la interfaz anfitrión y la interfaz virtual que se ha creado. Esta acción se muestra en la ventana de la Figura 1.

Figura 1

En esta ventana se ha seleccionado la opción Interface Anfirtión en el apartado Conectar a y se ha incluido vbox0 en el apartado Nombre de la Interface. Para la segunda máquina virtual habría que incluir vbox1 en el apartado Nombre de la Interface y mantener el resto de parámetros de la Figura 1.

Si sólo se va a utlizar una máquina virtual en el equipo anfitrión, habría que omitir toda la configuración realizada para la interfaz virtual vbox1.

Conviene recordar que el usuario que va a ejecutar las máquinas virtuales debe ser miembro del grupo vboxusers.

Un último apunte. Si vamos a utilizar las máquinas virtuales con otros usuarios, hay que crear las interfaces virtuales para estos usuarios. Hay que tener en cuenta que el permiso de utilización de la interfaz virtual se asigna cuando es creada, utilizando la orden VBoxAddIF vbox0 coralio br0. Por ejemplo, si el usuario pepe utilizara una máquina virtual, no podría usar las interfaces virtuales creadas para otro usuario y tendría que utilizar la suya propia. Para ello, habría que ejecutar la orden VBoxAddIF vbox2 pepe br0. Además, en la configuración de red de su máquina virtual (Figura 1), habría que incluir vbox2 en el apartado Nombre de la Interface. No olvidar modificar el archivo /etc/network/interfaces y añadir la interfaz vbox2 en el bloque de la interfaz bridge br0, quedando como sigue: bridge_ports eth0 vbox0 vbox1 vbox2.

Como no podía se de otra forma, Sun Microsystems, a partir de la versión 2.1.2 de VirtualBox, ha simplificado esta configuración de la red. En este artículo he publicado el nuevo método.