"Después del juego es antes del juego"
Sepp Herberger

lunes, 16 de febrero de 2015

¡Desperta, ferro!

En los IES de Extremadura tenemos en funcionamiento muchísimos viejos Pentium IV de hace 13 años como puestos Linux. El sistema en funcionamiento se basa en LTSP: el ordenador del profesor hace de servidor de aula y los equipos de los alumnos son clientes LTSP suyos. El sistema nos permite ejecutar las últimas versiones de software en equipos con 256Mb-512Mb de RAM y sin necesidad de disco duro. Un estupendo ahorro para todos los contribuyentes.

Una parte muy importante del sistema es que los equipos de los alumnos puedan ser encendidos mediante WakeOnLan desde el equipo del profesor, ya que están dentro de cajas cerradas. El servidor grita "¡Desperta, ferro!" cual soldado almogávar, y los thinclients se encienden y cargan el sistema operativo por la tarjeta de red mediante el protocolo PXE.

En mi caso tengo como thinclients los incombustibles Fujitsu P300, tan duros e inmunes a la obsolescencia programada que parecen hechos en la RDA.  Estos PC siempre habían funcionado sin problema hasta la versión 2.6.32 del kernel de Linux. A partir de ahí, el WakeOnLan dejó de funcionar. Como solución temporal nos quedamos un tiempo con la versión 2.6.32, pero es una medida intolerable ya que el kernel de Linux sigue evolucionando y no podemos quedarnos atrás.

El problema venía del driver de la tarjeta ethernet de los equipos. El lspci nos dice:

02:01.0 Ethernet controller [0200]: ADMtek NC100 Network Everywhere Fast Ethernet 10/100 [1317:0985] (rev 11)
    Subsystem: Fujitsu Technology Solutions Scenic N300 ADMtek AN983 10/100 Mbps PCI Adapter [1734:100c]
    Flags: bus master, fast Back2Back, medium devsel, latency 64, IRQ 23
    I/O ports at 3000 [size=256]
    Memory at d0100000 (32-bit, non-prefetchable) [size=1K]
    [virtual] Expansion ROM at 40000000 [disabled] [size=128K]
    Capabilities: [c0] Power Management version 2
    Kernel driver in use: tulip

El driver tulip es el que maneja esta tarjeta. Una cosa curiosa que pasaba en el kernel 2.6.32 y anteriores es que dicho driver no daba soporte WOL. Es decir, si hacías:

ethtool -s eth0 wol g

Te daba un error diciendo que el driver no soportaba eso. Lo gracioso es que el WOL estaba activo por defecto y funcionaba, aun cuando el driver no lo manejase. ¿Qué pasó en las versiones posteriores a la 2.6.32?: pues que alguien metió soporte para WOL dentro del driver. Ahora:

ethtool -s eth0 wol g

si funcionaba y no daba error, pero en la práctica los equipos desoían la petición de encenderse. En ninguna de las versiones posteriores de kernels (series 2.x y 3.x) se solucionó esto. Abrí una petición en sourceforge al desarrollador del driver y no me contestó. El driver sigue casi inmutable kernel tras kernel, con el WOL sin funcionar para nuestras tarjetas. Descargando el código fuente del kernel el correspondiente driver está en drivers/net/ethernet/dec/tulip/ y dentro de allí el fichero crítico es tulip_core.c. Ese es el lugar donde se ha implementado el soporte WOL.

Hacer una depuración del driver y ver que fallaba es algo que escapa a mis conocimientos y tiempo disponible, así que se me ocurrió otra cosa: ¿por qué no quitaba del driver todo lo añadido, recompilaba y cruzaba los dedos?. Para ello comparé el tulip_core.c de la versión 2.6.32 con el de la versión 3.2.0-4, que era el kernel con el que trabajaba, usando la utilidad de comparación de ficheros meld.

La verdad es que había bastantes diferencias, pero comentando partes, compilando, probando, obteniendo diversos alarmantes avisos de kernel panic y otros (segmentation fault,  apocalypse now, Venezuela-ETA-Podemos, Winter is coming, etc....), y volviendo a empezar varias veces di con el tulip_core.c correcto. Había conseguido quitar el soporte WOL, con lo que:

ethtool -s eth0 wol g

volvía a dar error, pero el WOL funcionaba de nuevo :-). Increíble: para que funcione una feature hay que eliminar la implementación de dicha feature. Me encanta la informática.

El tulip_core.c modificado que me funcionó está en este enlace.  Funciona para kernels 3.2.0-4, pero sospecho que compilará sin mayor problema en kernels superiores. En cualquier caso para adaptarlo a otros kernel habría que comentar las mismas partes que he comentado en el tulip_core.c para el kernel 3.2.0-4, comparando con el tulip_core.c original. Quizá sustituyendo directamente el tulip_core.c por el que se enlaza funcione sin más, ya que es un driver que no cambia mucho.

Antes de nada, bajamos del enlace anterior el fichero tulip_core.c modificado y lo guardamos en una carpeta /root/tulip del PC donde vayamos a realizar la compilación, un equipo Fujitsu P300 en mi caso. Los pasos a dar para compilar el driver tulip son los siguientes:

1) Confirmamos la versión del kernel y bajamos las cabeceras y el código fuente:

# apt-get update
# cat /proc/version
Linux version 3.2.0-4-686-pae (debian-kernel@lists.debian.org) (gcc version 4.6.3 (Debian 4.6.3-14) ) #1 SMP Debian 3.2.65-1+deb7u1
# apt-get install linux-headers-3.2.0-4-686-pae
# apt-get install linux-source-3.2

2) Descomprimimos el kernel y antes de seguir hacemos una copia del driver original (tulip.ko) por si metemos la pata poder restaurarlo luego. La copia se hace a un directorio /root/tulip que hemos creado previamente.

# cd /usr/src/
# tar jfvx linux-source-3.2.tar.bz2
# cd /lib/modules/3.2.0-4-686-pae/kernel/drivers/net/ethernet/dec/tulip/
# cp tulip.ko /root/tulip/tulip-original.ko

3) Volvemos al código fuente y preparamos el entorno de compilación, indicamos que haremos uso de la configuración del kernel actualmente en funcionamiento:

# cd /usr/src/linux-source-3.2/
# make distclean; yes "" | make oldconfig
# make prepare
# make modules_prepare
# cp /usr/src/linux-headers-3.2.0-4-686-pae/Module.symvers .

4) Hacemos una copia del tulip_core.c original a /root/tulip/tulip_core.c.original y machacamos éste con /root/tulip/tulip_core.c, que es dónde hemos descargado el fichero modificado desde el enlace anteriormente indicado.

# cd /usr/src/linux-source-3.2/drivers/net/ethernet/dec/tulip/
# mv tulip_core.c  /root/tulip/tulip_core.c.original
# cp /root/tulip/tulip_core.c .

5) Bueno, ahora lanzamos la compilación:

# cd /usr/src/linux-source-3.2/
# make M=drivers/net/ethernet/dec/ clean
# make M=drivers/net/ethernet/dec/ modules

El parámetro M=drivers/net/ethernet/dec/ es muy útil para compilar solamente el driver tulip (ubicado en drivers/net/ethernet/dec) y no el kernel completo, ya que tarda una eternidad en hacerse.

6) Una vez compilado con éxito, guardamos el driver generado por si acaso y lanzamos la instalación del mismo:

# cp /usr/src/linux-source-3.2/drivers/net/ethernet/dec/tulip/tulip.ko /root/tulip/tulip-sinwol.ko
# make M=drivers/net/ethernet/dec/ modules_install

7) Veamos si se ha instalado:

#ls -1 /lib/modules/
3.2.0-4-686-pae
3.2.65

Bueno, pues parece que en la carpeta 3.2.0-4-686-pae está el driver antiguo y en la carpeta 3.2.65 el driver nuevo (la compilación de los drivers del kernel bajado desde fuentes se guarda en una carpeta distinta al instalarse para no colisionar con los que ya tenemos). Esto va bene.

8) Prosigamos: regeneramos las dependencias de módulos y metemos el módulo nuevo en en initramfs, reiniciando luego.

# depmod -a
# update-initramfs -u
# reboot

9) Al arrancar de nuevo hacemos:

# ethtool -s eth0 wol g

Carajo, no da error diciendo que no hay soporte ethtool, como debería ser. Se ha cargado el driver antiguo otra vez. Tranquilidad: por defecto se carga el driver tulip.ko de /lib/modules/3.2.0-4-686-pae y no el de /lib/modules/3.2.65. Tenemos dos opciones:

  • La fuerza bruta: machacar el driver antiguo con el nuevo, escribiendo:
# cp /root/tulip/tulip-sinwol.ko /lib/modules/3.2.0-4-686-pae/kernel/drivers/net/ethernet/dec/tulip/tulip.ko
# depmod -a
# update-initramfs -u
# reboot

o

# cp /lib/modules/3.2.65/extra/tulip/tulip.ko /lib/modules/3.2.0-4-686-pae/kernel/drivers/net/ethernet/dec/tulip/tulip.ko
# depmod -a
# update-initramfs -u
# reboot
  • Decirle al sistema que cargue antes los drivers actualizados que los propios del kernel. Para ello editamos /etc/depmod.conf y dejamos la primera línea así:
search updates built-in
....

y luego, otra vez:

# depmod -a
# update-initramfs -u

Pues nada, reiniciamos y el ethtool ahora debe dar nuestro esperado error. Si apagamos el equipo y mandamos un wakeonlan a su MAC desde otro PC nuestro ferro P300 despertará.

Y con esto y un bizcocho, hasta la semana que viene a las 8.

Actualización:

  • El usar /etc/depmod.conf para hacer que nuestro módulo se cargue antes que el que viene con el kernel por defecto no funciona en Debian Wheezy. Ese fichero ha desaparecido inexplicablemente. He leído algo sobre usar /etc/depmod.conf.d/* (que tampoco existe) y crear alli un fichero con el contenido de depmod.conf, pero no lo he probado. Recomiendo por tanto la primera solución: sobreescribir el driver original. A fin de cuentas tenemos copia.
  • Con un kernel de backports de wheezy, el 3.16, la compilación del driver no funciona. La orden:
# make M=drivers/net/ethernet/dec/ modules

Da un error en tulip_core.c, cuando compilaba perfectamente con kernel 3.2. La causa es que pasa a tratar como "error" cosas que antes eran "warning". Para solucionarlo hay que editar el fichero tulip_core.c y cambiar:

SET_ETHTOOL_OPS(dev, &ops);

por

dev->ethtool_ops = &ops;

 

2 comentarios:

  1. Muy útil para quien arrastre la losa de administrar un Fujitsu P300 (losa literal si además tienes que moverlo de sitio).

    En xubuntu, la única diferencia significativa fué, para lanzar la compilación :

    cd /usr/src/linux-3.13/drivers/net/ethernet/dec/

    make -C /lib/modules/3.13.0-74-generic/build M=$(pwd) modules

    Y la instalación a la brava, como indicas (cp, depmod, update-initramfs).

    El fuente sólo ha cambiado con respecto al que modificaste en un parámetro que ahora es una constante (6 <-> ETH_ALEN, creo); comparé ambos a ojo para adaptar el nuevo, pero imagino que sobreescribiendo con el tuyo habría funcionado también.

    Por cierto, el source tuve que bajarlo de : http://packages.ubuntu.com/trusty/linux-source-3.13.0, descomprimiendo tar y diff, y aplicando el último con patch -p1 -i linux_3.13.0-74.118.diff; instalando el paquete linux-source-3.13.0 no trae Module.symvers y daba errores al compilar (aunque eso fue al principio, puede que no fuese necesario).

    Gracias, un saludo :)

    ResponderEliminar
  2. Gracias por la chuleta, Oscar, ya tenemos de nuevo WOL para nuestras aulas de thinclients. Larga vida a nuestros P300, ¡a ver si conseguimos ejecutar Ubuntu 19.04 en ellos!.

    ResponderEliminar