¡Esta es una revisión vieja del documento!
Tabla de Contenidos
LPI Topic 201: Linux Kernel
- 201.1: Kernel Components (2)
- 201.2: Compiling a kernel (3)
- 201.3: Kernel runtime management and troubleshooting (4)
Kernel Components
El kernel de Linux es el responsable de la gestión del hardware. Es el núcleo del sistema donde se detecta todo el hardware y se cargan los controladores que sirven para que el hardware se comunique con el sistema.
Actualmente, el kernel tiene una estructura modular y solo se cargan en memoria los módulos necesarios para el correcto funcionamiento del sistema (originalmente el diseño del kernel era monolótico, es decir, contenía todos los controladores sin importar si el sistema utilizaba ese hardware)
Componentes del kernel:
- El núcleo del kernel.
- Módulos
- Ramdisk (memoria para descomprimir el kernel en el momento en que se ejecuta)
Cuando se almacenan en disco, la mayoría de las imágenes del kernel se comprimen para ahorrar espacio. Hay dos tipos de compresión del kernel:
- zImage: tiene un tamaño máximo de 502 kB (loaded into low memory)
- bzImage: no tiene límite de tamaño, preferido para los kernel grandes (loaded into high memory)
Tanto zImage como bzImage utilizan la compresión gzip. El bz de bzImage se refieres a big zImage, no al algoritmo de compresión bzip.
Cuando se arranca el equipo, al llegar al cargador de arranque (GRUB, por ejemplo), este selecciona el kernel adecuado y lo descomprime sobre la ramdisk.
Nomenclatura del kernel
El kernel de Linux lo encontramos en un archivo llamad mvlinuz-A.B.C-D dentro de la partición /boot.
Hay 3 esquemas diferentes para la numeración de versiones:
- Hasta la 2.6.0:
- A: major release
- B: minor release (número par: estable; impar: desarrollo)
- C: patch level
- Desde 2.6.0 hasta 3.0
- C: número incrementado cada 2 o 3 meses
- D: solución de bugs e incidencias de seguridad
- Versión 3.0 y 4:
- B: version number
- C: patch level.
Para saber la versión del kernel en uso:
uname -r
Más información:
uname -a
Fuentes del kernel
Si queremos hacer nosotros la compilación del kernel, necesitamos descargar su código fuente que normalmente se almacenará en /usr/src/<VERSION_KERNEL>
Para descargar las fuentes del kernel: https://www.kernel.org/
La documentación estaría en /usr/src/<VERSION_KERNEL>/Documentation
Categoría de lanzamientos de kernel
Ediciones sobre las que se lanzan los kernels:
- Prepatch: aún en pruebas
- Mainline: línea principal
- Stable: estable
- Longterm:
Módulos
Son como los drivers, programas que nos permitirán que el sistema detecte y se comunique con el hardware.
Los módulos se pueden cargar dinámicamente, es decir, con el kernel funcionando, podemos decidir qué módulos cargar.
Tiene extensión ko y se almacenan en /lib/modules/<VERSION_KERNEL>. Por ejemplo, para ver un módulo para un dispositivo puente de red: /lib/modules/4.19.0-14-amd64/kernel/net/bridge/bridge.ko
La configuración de los módulos para una versión del kernel instalada se encuentra en /boot/config-kernel-<VERSION_KERNEL>
Ramdisk
Disco virtual sobre el que se descomprime el kernel al arrancar. Este disco virtual es el fichero initrd.img-<VERSION_KERNEL>
Compiling a kernel
Pasos:
- Obtener fuentes del kernel
- Herramientas para compilación
- Limpieza
- Configuración
- Compilación
Obtención de fuentes
El primer paso es obtener las fuentes del kernel: https://kernel.org, eligiendo el enlace de tarball. El fichero puede tener extensión tar.xz o tar.gz, es decir, es un paquete comprimido.
Para descomprimirlo, en caso de tar.xz tendremos que hacer dos pasos:
unxz <FUENTES_KERNEL.tar.xz>
Y desempaquetamos:
tar xvf <FUENTES_KERNEL.tar> -C /usr/src/
En caso de tar.gz:
tar zxvf <FUENTES_KERNEL.tar.gz> -C /usr/src/
Una vez descomprimido, las fuentes del kernel deben quedar en /usr/src/linux-<VERSION_KERNEL>
Herramientas para compilación
En Debian es necesario instalar:
apt-get install build-essential bison flex libelf-dev libssl-dev bc libncurses5-dev
En CentOS:
yum group install "Development Tools"
Es posible que hagan falta más herramientas, pero eso lo sabremos cuando empecemos a compilar y nos aparezcan errores.
Limpieza
Para asegurarnos de que comenzamos con un estado limpio del kernel, debemos realizar la limpieza del mismo:
make mrproper
Debemos realizar la operación dentro del directorio con las fuentes del kernel que vamos a compilar
Generar archivo de configuración
La compilación se realiza en función de la información albergada en el archivo .conf que se encuentra en la raíz del directorio de las fuentes. Para generar este fichero:
make menuconfig
Debemos realizar la operación dentro del directorio con las fuentes del kernel que vamos a compilar
Después de hacer los cambios, cuando guardamos y salimos, se generará un fichero .config (si hemos dejado el nombre por defecto)
Compilación
La compilación se realiza ejecutando el comando make:
make
Debemos realizar la operación dentro del directorio con las fuentes del kernel que vamos a compilar
Este proceso dura un tiempo que dependerá de la potencia del equipo donde se haga la compilación.
bzImage
Tras una compilación satisfactoria, debemos crear la imagen:
make bzImage
Debemos realizar la operación dentro del directorio con las fuentes del kernel
Se creará en /usr/src/<VERSION_KERNEL>/arch/x86/boot/bzImage
Instalación de módulos
make modules
Y tras ello:
make modules_install
Los módulos se instalarán en la carpeta /lib/modules/<VERSION_KERNEL>
En versiones antiguas (antes del kernel 3.0), se utiliza make dep
Instalación del kernel
Al finalizar los pasos anteriores, tendríamos:
- 32 bits:
/usr/src/<VERSION_KERNEL>/arch/x86/boot/bzImage - 64 bits:
/usr/src/<VERSION_KERNEL>/arch/x86_64/boot/bzImage
La instalación se hace copiando simplemente dicho archivo a /boot y se renombra con el formato que tengan las otras imágenes en ese directorio:
cp /usr/src/<VERSION_KERNEL>/arch/x86_64/boot/bzImage /boot/vmlinuz-<VERSION_KERNEL>
Finalmente también tendríamos que añadir los ficheros System.map y .config:
cp /usr/src/<VERSION_KERNEL>/System.map /boot/System.map-<VERSION_KERNEL> cp /usr/src/<VERSION_KERNEL>/.config /boot/config-<VERSION_KERNEL>
Creación del Ramdisk
Tenemos que dejar a disposición del kernel un ramdisk que contenga el conjunto de módulos compilados para la nueva versión del nuevo kernel:
mkinitramfs -o NOMBRE_IMAGEN_VERSION
Anteriormente se utilizaba el comando mkinitrd
Ejemplo:
mkinitramfs -o initrd.img-4.16.7
Configurar el gestor de arranque
Tenemos que indicarle al gestor de arranque que hay un nuevo kernel para que nos permita elegirlo y arrancarlo. Aquí veremos el ejemplo del cargador de arranque GRUB.
Entramos en /boot/grub.d y editamos, por ejemplo, el fichero llamado 40_custom:
menuentry 'Debian GNU/Linux, with Linux 4.16.7' {
# Partición del disco donde está el sistema
set root='hd0,msdos1'
# Kernel a usar
linux /boot/vmlinuz-4.16.7 root=/dev/sda1 ro single
# Ramdisk donde se descomprimirá el kernel
initrd /boot/initrd-4.16.7
}
El primer disco es hd0. Y las particiones empiezan a partir del 1. Si el sistema de particiones es MBR, será msdos. hd0,msdos1. Primer disco, MBR y primera partición.
Generamos el nuevo fichero de configuración del GRUB (/boot/grub/grub.cfg):
grub-mkconfig -o grub.cfg
Aplicar los cambios:
update-grub
Kernel runtime management and troubleshooting
Gestión de módulos
lsmod
Lista módulos instalados en el kernel y qué procesos los están usando. Muestra la misma información que el contenido de /proc/modules
Module Size Used by video 49152 0 x_tables 45056 1 ip_tables mbcache 16384 1 ext4 (...)
insmod
Insertar (cargar) módulos en el kernel.
insmod /lib/modules/4.16.7/kernel/drivers/net/sb1000.ko
Luego podemos verificar que está instalado con lsmod
rmmod
Eliminar módulos del kernel.
rmmod <NOMBRE_MODULO>
Si el módulo está en ejecución o depende de otro módulo, no nos dejará.
modprobe
Realiza la gestión dinámica de módulos. Realiza las mismas operaciones que lsmod, insmod y rmmod, pero da más opciones:
l: lista todos los módulos disponiblesa: inserta todos los módulosr: elimina un módulo y sus dependencias
Ejemplo:
modprobe sym53c8xx.ko
Insertaría un módulo, resolviendo las dependencias.
modinfo
Muestra información sobre módulos
modinfo /lib/modules/4.16.7/kernel/drivers/net/sb1000.ko
Ejemplo de salida:
filename: /usr/lib/modules/4.19.0-14-amd64/kernel/drivers/net/sb1000.ko license: GPL description: General Instruments SB1000 driver author: Franco Venturi <fventuri@mediaone.net> alias: acpi*:GIC1000:* alias: pnp:dGIC1000* depends: retpoline: Y intree: Y name: sb1000 (...)
Configuración de módulos
La configuración de los módulos están en los siguientes ficheros:
/etc/modules.conf/etc/modprobe.conf/etc/modprobe.d/*.conf
El primero está obsoleto en muchas distribuciones y modprobe.conf no suele estar por defecto en el sistema.
Dependencias de módulos
El archivo que define las dependencias de unos módulos con respecto a otros es modules.dep que se encuentra en /lib/modules/<VERSION_KERNEL>
Aspecto del fichero modules.dep:
kernel/arch/x86/crypto/glue_helper.ko: kernel/arch/x86/crypto/twofish-x86_64-3way.ko: kernel/arch/x86/crypto/twofish-x86_64.ko kernel/crypto/twofish_common.ko kernel/arch/x86/crypto/glue_helper.ko (...)
Primero aparece el nombre del módulo y a continuación los módulos de los que depende.
Carga de módulos
kmod y kerneld se encargan de la carga dinámica de módulos del kernel. El módulo se carga cuando el kernel lo necesita.
kmod: hilo propio del kernel y opera directamente con él.kerneld: es una daemon y se comunica con el kernel a través de SysV.
Ambos usan modprobe para manejar dependencias y cargas dinámicas de módulos.
Kmod reemplaza Kerneld a partir del kernel 2.2
Para habilitar el uso de kmod, el kernel debe ser compilado con la opción CONFIG_KMOD habilitada (es la opción por defecto). Esto es porque kmod se implementa como un módulo del kernel y dicho módulo debe ser habilitado también.
Hardware e información del kernel
lsdev
Proporciona información del hardware instalado. Qué dispositivo está usando qué dirección I/O y canales IRQ/DMA. Para ello, utiliza la información de los siguientes ficheros:
/proc/interrupts/proc/ioports/proc/dma
Para tener disponible este comando, hay que instalar el paquete procinfo (en Debian)
lscpi
Muestra información sobre todos los buses PCI del sistema y todos los dispositivos que están conectados a ellos.
lsusb
Muestra información de los buses USB de sistema y los dispositivos que están conectados a ellos.
dmesg
Comando que permite ver los mensajes de la salida estándar del kernel (también llamado kernel buffer ring).
Muy útil para tratar de solucionar problemas con el sistema o si necesitamos obtener información del hardware del sistema.
La salida de dmesg normalmente se puede encontrar en /var/log/dmesg (o /var/log/messages).
Como la salida del comando es muy larga, lo normal es filtrar los resultados con grep:
dmesg | grep sda
Ejemplo de salida:
[ 3.166003] sd 1:0:0:0: [sda] 134217728 512-byte logical blocks: (68.7 GB/64.0 GiB) [ 3.166043] sd 1:0:0:0: [sda] Write Protect is off [ 3.166045] sd 1:0:0:0: [sda] Mode Sense: 00 3a 00 00 [ 3.166057] sd 1:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA [ 3.195329] sda: sda1 sda2 < sda5 > [ 3.196275] sd 1:0:0:0: [sda] Attached SCSI disk [ 14.208926] EXT4-fs (sda1): mounting ext2 file system using the ext4 subsystem [ 14.215321] EXT4-fs (sda1): mounted filesystem without journal. Opts: (null)
sysctl
Modifica los parámetros del kernel en tiempo de ejecución:
sysctl net.ipv4.ip_forward=1
Los parámetros disponibles se encuentra en /proc/sys/. Para el ejemplo anterior, estarían en /proc/sys/net/ipv4/. Si queremos ver si está activado o no, abrimos el fichero. Por ejemplo, si abrimos /proc/sys/net/ipv4/ip_forward veremos un 0 si no está activado y un 1 si lo tenemos activado.
Los cambios son volátiles, desaparecerán al apagar/reiniciar el equipo. Si se quiere mantener los cambios, hay que añadir los parámetros en el fichero /etc/sysctl.conf
Si queremos ver todos los parámetros disponibles y su estado:
sysctl -a
Ejemplo de salida:
abi.vsyscall32 = 1 crypto.fips_enabled = 0 debug.exception-trace = 1 debug.kprobes-optimization = 1 dev.hpet.max-user-freq = 64 dev.mac_hid.mouse_button2_keycode = 97 dev.mac_hid.mouse_button3_keycode = 100 dev.mac_hid.mouse_button_emulation = 0 dev.scsi.logging_level = 0 dev.tty.ldisc_autoload = 1 fs.aio-max-nr = 65536 (...)
udev
Detecta los dispositivos del sistema y está diseñado para hacer más flexible y seguro el manejo de dispositivos.
Consiste en un daemon udevd que recibe uevent desde el kernel. La comunicación se realiza mediante el sistema de ficheros virtual /sys.
El fichero de configuración es /etc/udev/udev.conf.
El directorio donde se almacenan las reglas definidas por el usuario se encuentra en /etc/udev/rules.d
udevadm
Control de udev en tiempo de ejecución
udevmonitor
Comando que muestra los eventos de udev y el kernel por la salida estándar.
Se puede utilizar para analizar la frecuencia de eventos medidante la comparación del tiemstamp del uevent kernel y el evento udev.
No existe en todas las distribuiciones linux. Cuando existe, suele ser un enlace simbólico a udevadm monitor
