DKMS
DKMS : Donnez l'indépendance à vos pilotes
Contexte
Sous Linux, les pilotes (le logiciel qui permet au système d'exploitation de communiquer avec le matériel) peuvent soit être directement inclus dans le noyau soit être disponibles sous la forme de modules à charger dans le noyau. Un tel module est compilé pour un noyau particulier et ne peut être utilisé sur un autre.
En ce qui concerne les pilotes libres, cela ne pose en général aucun problème car ils sont soit livrés avec votre noyau, soit compilés en même temps que le noyau que vous compilez vous-même.
Dans le cas de pilotes non libres (comme ceux de nVidia ou ATI) ou de pilotes distribués séparément et que vous compilez à la main, le pilote doit être recompilé à chaque version de noyau, ce qui peut devenir fastidieux.
De plus, si vous souhaitez utiliser les pilotes distribués par votre distributeur Linux, vous devez attendre que les pilotes soient recompilés pour le nouveau noyau, et ne pouvez espérer qu'ils fonctionnent avec un noyau que vous auriez personnalisé.
Objectifs de DKMS
DKMS (Dynamic Kernel Module Support ou en français Gestion Dynamique des Modules Noyau) est un système très simple conçu par Dell et permettant de compiler dynamiquement et facilement les modules noyau pour tous les noyaux de votre système. Ce système est à la base conçu pour faciliter à Dell la distribution de pilotes Linux et de correctifs.
Cela évite à la fois aux éditeurs et aux utilisateurs de devoir passer par des mises à jour du noyau pour une correction sur un pilote particulier et permet de distribuer un pilote supplémentaire sous la forme d'un seul paquetage quel que soit le noyau de l'utilisateur.
Cet article a pour but de présenter ce système, à la fois aux développeurs et distributeurs de modules noyau qui pourraient l'utiliser pour faciliter la vie à leurs utilisateurs, et aux utilisateurs qui peuvent également l'utiliser tout seuls.
Comment ça marche
Le principe de DKMS est très simple. À condition que le module soit prévu pour être utilisé avec DKMS (fourniture d'un dkms.conf), l'utilisation d'un nouveau module en passant par DKMS consiste à exécuter les 3 étapes suivantes :
- Insertion dans l'arbre DKMS (action add)
- Compilation pour le noyau (action build)
- Installation avec les autres modules du noyau (action install)
Ces étapes sont séparées et ne sont pas forcement toutes réalisées à la suite. La figure 1 montre les différents états d'un module dans le système DKMS, et les transitions possibles entre ces états à l'aide des actions de la commande dkms. Figure 1 : États d'un module dans DKMS Figure 1 : États d'un module dans le système DKMS
Structure sur le disque
Afin de bien séparer la gestion des différentes versions de module et de la version du noyau, le fonctionnement de DKMS se base sur la présence de 3 arborescences :
- Les sources des modules, dans /usr/src
- L'arborescence des modules du noyau/lib/modules : DKMS y remplacera ou ajoutera les modules que l'on va lui faire gérer
- L'arborescence de DKMS /var/lib/dkms, contenant :
o Les répertoire ou seront construit les modules o Les modules originaux sauvegardés o Les modules générés par DKMS
Les chemins indiqués sont ceux par défaut et il est possible de les modifier dans /etc/dkms/framework.conf mais nous supposerons dans le reste de l'article que les valeurs par défaut ont été conservées.
Mise en oeuvre de DKMS par un utilisateur
La commande dkms
La gestion des modules au sein du système DKMS se fait à l'aide de la commande dkms. Cette commande a une syntaxe très simple : dkms <action> [options] Les actions et les options sont par contre plutôt nombreuses et même si je vous les explique ci-dessous, seules les principales devraient être utiles à la majorité d'entre vous (à savoir: add, build, install, remove en ce qui concerne les actions et -m, -v et --all en ce qui concerne les options).
Voici tout d'abord la liste des options génériques s'appliquant à diverses commandes, celles restreintes à une commande particulière seront expliquées dans la description de celle-ci.
- -m <module> : Le nom du module sur lequel effectuer l'action.
- -v <version du module> : La version du module sur laquelle effectuer l'action.
- -k <version du noyau> : La version du noyau sur laquelle effectuer l'action. Il est possible pour certaines actions de spécifier plusieurs versions du noyau en utilisant plusieurs fois -k, si l'action spécifiée ne le supporte pas une erreur sera émise.
- -a <architecture> : L'architecture pour laquelle effectuer l'action. Si cette option n'est pas précisée, l'architecture choisie est celle indiquée par uname -m. Il est possible de répéter cette option afin d'indiquer plusieurs architectures, mais dans ce cas il doit y avoir exactement autant de -k que de -a. Chaque noyau sera associé à l'architecture de position identique. Par exemple si vous indiquez -k noyau1 -k noyau2 -a i386 -k noyau3 -a i586 -a x86_64, DKMS comprendra que noyau1 est en i386, noyau2 est en i586 et noyau3 est en x86_64.
- --all : Indique d'appliquer l'action pour toutes les versions de noyau et toutes les architectures pour lesquelles le module a été compilé. Cela est particulièrement utile pour l'action remove.
- --rpm_safe_upgrade : Cette option est nécessaire pour les commandes DKMS appelées à l'intérieur d'un RPM. Cela évite des problèmes lors de mise à jour d'un RPM à un autre contenant la même version du module. Cela évite aussi les problèmes d'interblocage dus au système de verrous de rpm.
Nous allons maintenant étudier ce que permet de faire DKMS à travers le parcours des actions que l'on peut faire effectuer à la commande dkms.
- add : Ajoute à l'arbre des sources de DKMS une version d'un module (les options -m et -v sont donc obligatoires, c'est le cas pour la majorité des commandes). Les sources du module doivent être précédemment placées dans /usr/src/<module>-<version du module>/ et contenir un fichier dkms.conf. Si le fichier dkms.conf ne se trouve pas dans /usr/src/<module>-<version du module>/, il faut ajouter l'option -c pour indiquer son chemin.
[root@plop src]# dkms add -m exemple -v 0.9.0 -c /tmp/dkms.conf
Creating symlink /var/lib/dkms/exemple/0.9.0/source ->
/usr/src/exemple-0.9.0
DKMS: add Completed.
- remove : Supprime une version d'un module. Il faut en plus des options -m et -v, soit préciser une version de noyau avec l'option -k, soit demander à supprimer le module de tout les noyaux pour lesquelles cette version avait été compilée, avec l'option --all.
Si le module avait été installé, il est d'abord désinstallé (comme si on avait appelé l'action uninstall) et d'éventuelles versions précédentes sont réinstallées. Après un remove, le module n'est plus du tout connu de DKMS et il faut recommencer à l'étape add.
[root@plop src]# dkms remove -m exemple -v 0.9.0 --all
Deleting module version: 0.9.0
completely from the DKMS tree.
Done.
- build : Compile une version d'un module pour le noyau indiqué avec l'option -k ou pour le noyau utilisé actuellement si aucun n'est précisé. En cas d'erreurs lors de la compilation, il est utile de savoir que celle-ci se déroule dans /var/lib/dkms/<module>/<version du module>/build/ et que tout ce qui est affiché pendant la compilation est enregistré dans un fichier make.log dans ce même répertoire.
La commande build accepte quelques options facultatives : o --config <fichier .config du noyau> : Cette option permet d'indiquer à la commande build ou trouver le fichier .config si celui-ci n'est pas à l'emplacement standard de la distribution ou n'a pas le nom habituel. o --no-prepare-kernel : Cette option demande à DKMS de ne pas préparer les sources du noyau avant de compiler un module pour lui. Il est recommandé de ne pas utiliser cette option si l'on souhaite que les modules soient correctement construits. o --no-clean-kernel : Cette option demande à DKMS de ne pas nettoyer les sources du noyau après avoir compilé un module. o --kernelsourcedir <chemin vers les sources du noyau> : Cette option permet d'indiquer l'emplacement des sources du noyau lorsqu'elles ne se trouvent pas dans /lib/modules/<version du noyau>/build.
[root@plop src]# dkms build -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB
Preparing kernel 2.6.12-12mdk-i686-up-4GB for module build:
(This is not compiling a kernel, only just preparing kernel symbols)
Storing current .config to be restored when complete
Running Generic preparation routine
make mrproper.........
using /boot/config-2.6.12-12mdk-i686-up-4GB
make oldconfig......
make prepare-all......
Building module:
cleaning build area....
make KERNELRELEASE=2.6.12-12mdk-i686-up-4GB KERNEL_DIR=/lib/modules/2.6.12-12mdk-i686-up-4GB/build drivers....
cleaning build area....
cleaning kernel tree (make mrproper)....
DKMS: build Completed.
- install : Installe une version d'un module dans l'arborescence du noyau indiqué (ou du noyau utilisé actuellement si aucun n'est précisé par l'option -k). Cette version doit précédemment avoir été compilée pour le noyau en question à l'aide de l'action build.
Lors de la première installation d'une version d'un module donné sur un noyau donné, DKMS cherche si ce module existait déjà avec ce noyau et le sauvegarde pour pouvoir le réinstaller lorsque l'on demandera à DKMS de désinstaller la nouvelle version. Pour information, la version originale est sauvée dans /var/lib/dkms/<module>/original_module/<version du noyau>/<architecture>/
[root@plop src]# dkms install -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB
Running module version sanity check.
slamr.ko.gz:
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/2.6.12-12mdk-i686-up-4GB/kernel/drivers/char/
slusb.ko.gz:
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/2.6.12-12mdk-i686-up-4GB/kernel/drivers/char/
depmod.....
DKMS: install Completed.
- uninstall : Désinstalle une version d'un module pour une version du noyau (celle précisée par l'option -k ou la version utilisée actuellement si aucune n'est précisée). Cette commande ne gère pas l'option --all donc il vous faudra désinstaller pour chaque noyau séparément.
[root@plop src]# dkms uninstall -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB
Uninstall Beginning --------
Module: slmodem
Version: 2.9.10
Kernel: 2.6.12-12mdk-i686-up-4GB (i586)
Status: Before uninstall, this module version was ACTIVE on this kernel.
slamr.ko.gz:
- Uninstallation
- Deleting from: /lib/modules/2.6.12-12mdk-i686-up-4GB/kernel/drivers/char/
- Original module
- No original module was found for this module on this kernel.
- Use the dkms install command to reinstall any previous module version.
slusb.ko.gz:
- Uninstallation
- Deleting from: /lib/modules/2.6.12-12mdk-i686-up-4GB/kernel/drivers/char/
- Original module
- No original module was found for this module on this kernel.
- Use the dkms install command to reinstall any previous module version.
DKMS: uninstall Completed.
- mkrpm : Génére un RPM pour un couple module/version donné. Si vous désirez que le RPM ne contienne que les sources (et donc que les modules soient compilés lors de l'installation), vous devez ajouter l'option --source-only. Sinon, le choix des modules à distribuer se fait à l'aide de -k et -a, comme pour les autres actions.
Si vous maîtrisez la création de RPM et souhaitez personnaliser ce qui est généré, sachez que DKMS regarde d'abord si /usr/src/<module>-<version du module>/<module>-dkms-mkrpm.spec existe, si oui l'utilise comme modèle, et sinon utilise /etc/dkms/template-dkms-mkrpm.spec.
- status : Affiche l'état des différents modules pour chaque version, noyau et architecture.
[root@plop src]# dkms status
ipw2200, 1.0.4: added
slmodem, 2.9.10, 2.6.12-11mdk-i686-up-4GB, i586: installed
slmodem, 2.9.10, 2.6.12-12mdk-i686-up-4GB, i586: built
sysprof, 1.0, 2.6.12-12mdk-i686-up-4GB, i586: installed
- match : Cette commande fort sympathique permet de compiler et installer pour un noyau donné tout les modules qui avaient été installés pour un autre noyau (spécifié par l'option --templatekernel). Par exemple, après exécution de dkms match --templatekernel 2.6.12-11mdk-i686-up-4GB -k 2.6.12-12mdk-i686-up-4GB, toutes les combinaisons module/version qui étaient installées pour le noyau 2.6.12-11mdk-i686-up-4GB le seront pour le noyau 2.6.12-12mdk-i686-up-4GB.
- mktarball : Crée une archive tar.gz pour le module et la version indiquées. Cette archive contiendra les sources et les modules précédemment compilés. Par défaut l'archive est créée pour le noyau utilisé actuellement. Si vous en souhaitez un (ou plusieurs) autre, vous pouvez l'indiquer en utilisant les options -k et -a. Cette commande dispose également de quelques options supplémentaires :
o --archive <fichier.tar.gz> : Permet de préciser le nom à donner à l'archive (ne pas indiquer de chemin, il sera toujours placé dans /var/lib/dkms/<module>/<version du module>/tarball/). Sans cette option, le fichier s'appelle <module>-<version du module>-<versions des noyaux>.dkms.tar.gz o --binaries-only : Ne pas inclure les sources du module o --sources-only : Ne pas inclure les modules pré compilés. L'archive s'appellera <module>-<version du module>-source-only.dkms.tar.gz, sauf si vous précisez un autre nom à l'aide de --archive
[root@plop src]# dkms mktarball -m slmodem -v 2.9.10 -k 2.6.12-11mdk-i686-up-4GB -k 2.6.12-12mdk-i686-up-4GB
Marking modules for 2.6.12-11mdk-i686-up-4GB (i586) for archiving...
Marking modules for 2.6.12-12mdk-i686-up-4GB (i586) for archiving...
Marking /usr/src/slmodem-2.9.10 for archiving...
Tarball location: /var/lib/dkms/slmodem/2.9.10/tarball/slmodem-2.9.10-kernel2.6.12-11mdk-i686-up-4GB-i586-kernel2.6.12-12mdk-i686-up-4GB-i586.dkms.tar.gz
DKMS: mktarball Completed.
- ldtarball : Importe une archive tar.gz créé à l'aide de l'action mktarball et spécifié à l'aide de l'option --archive.
Les fichiers sont importés dans l'arborescence de DKMS et pas dans celle du noyau, les modules sont donc au mieux dans l'état built(compilé) et il faut lancer ensuite la commande dkms install pour chacun d'eux.
Par ailleurs, si des fichiers existent déjà lors de l'import, un avertissement sera affiché et ils seront laissés tels quels. Si vous souhaitez que ces éventuels fichiers soient écrasés, il faut ajouter l'option --force.
- mkdriverdisk : Crée une disquette avec les pilotes pour permettre l'installation d'une distribution, c'est particulièrement utile lorsque le CD d'installation ne contient pas les pilotes pour un nouveau contrôleur disque.
o --size <taille de la disquette> : Cette option est utilisée par la commande mkdriverdisk pour décider de la taille de la disquette à créer. La valeur doit être un nombre entier de kilo-octets, divisible par 20, et vaut 1440 si cette option n'est pas précisée. o --distrib <distribution> : Cette option obligatoire indique la distribution cible. Les valeurs actuellement supportées sont suse, UnitedLinux, redhat, redhat1 and redhat2. Red Hat supportant les disquettes de pilotes multi-architecture depuis la RHEL3, redhat1 force à utiliser l'ancien format, redhat2 force à utiliser le nouveau. o --release <version> : Cette option est nécessaire si vous construisez une disquette pour SuSE ou UnitedLinux. Elle indique la version de la distribution, par exemple --distrib suse --release 9.1 indiquera que vous construisez la disquette pour une SuSE 9.1 Les options --binaries-only et --sources-only de mktarball peuvent également être utilisées.
Utilisation basique
Après vous avoir noyé sous les commandes et les options, je pense qu'un exemple d'utilisation classique est nécessaire pour vous persuader de la simplicité d'utilisation. Voici donc comment installer un module exemple, fourni sous la forme de exemple-1.0.tar.gz contenant un unique répertoire exemple-1.0 avec les sources du module et un dkms.conf.
cd /usr/src
tar xzf /tmp/exemple-1.0.tar.gz
dkms add -m exemple -v 1.0
dkms build -m exemple -v 1.0
dkms install -m exemple -v 1.0
Listing 1 : Ajout d'un pilote en utilisant DKMS
Si tout s'est bien passé, le module est compilé et installé, et modprobe exemple fonctionne ! Si cela ne s'est pas bien passé, c'est vraisemblablement lors de l'étape build, et vous pouvez essayer de déterminer le problème en allant lire le fichier /var/lib/dkms/exemple/1.0/build/make.log. Si vous n'avez pas les compétences pour cela, le plus simple est d'envoyer ce fichier à l'auteur du dkms.conf afin qu'il corrige l'erreur.
Un mode de distribution courant, que nous détaillerons plus loin, consiste à distribuer les sources et le dkms.conf sous la forme d'un package RPM et non pas d'un tar.gz. Dans ce cas, installer le package RPM suffit et exécutera automatiquement les différentes commandes.
Mise en oeuvre de DKMS par un distributeur
Adaptation des sources
DKMS a besoin des sources du module dans le répertoire /usr/src/<nom du module>-<version du module>/ et d'un fichier dkms.conf dans ce même répertoire. Nous allons étudier la syntaxe de ce fichier sur un exemple classique avant de détailler toutes les options disponibles.
Exemple de dkms.conf pour l'ipw2200 1.0.4
PACKAGE_VERSION="1.0.4"
PACKAGE_NAME="ipw2200"
MAKE[0]="make -C ${kernel_source_dir} SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules HOSTAP_SRC=${kernel_source_dir}/3rdparty/hostap/"
CLEAN="make -C ${kernel_source_dir} SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build clean"
BUILT_MODULE_NAME[0]="$PACKAGE_NAME"
BUILT_MODULE_NAME[1]="ieee80211_crypt_ccmp"
BUILT_MODULE_NAME[2]="ieee80211_crypt"
BUILT_MODULE_NAME[3]="ieee80211_crypt_tkip"
BUILT_MODULE_NAME[4]="ieee80211_crypt_wep"
BUILT_MODULE_NAME[5]="ieee80211"
DEST_MODULE_LOCATION[0]="/kernel/drivers/net/wireless/ipw2200/"
DEST_MODULE_LOCATION[1]="/kernel/drivers/net/wireless/ipw2200/"
DEST_MODULE_LOCATION[2]="/kernel/drivers/net/wireless/ipw2200/"
DEST_MODULE_LOCATION[3]="/kernel/drivers/net/wireless/ipw2200/"
DEST_MODULE_LOCATION[4]="/kernel/drivers/net/wireless/ipw2200/"
DEST_MODULE_LOCATION[5]="/kernel/drivers/net/wireless/ipw2200/"
MODULES_CONF_ALIAS_TYPE[0]="eth"
REMAKE_INITRD="no"
AUTOINSTALL="yes"
Listing 2: Exemple de dkms.conf pour le pilote ipw2200 version 1.0.4
Comme vous pouvez le voir ce fichier a une syntaxe très simple, une option par ligne sous la forme OPTION="valeur". Voyons maintenant plus précisément à quoi correspondent les options définies dans cet exemple.
PACKAGE_VERSION et PACKAGE_NAME ne méritent je pense aucune explication. Il est toutefois intéressant de noter que lors de la sortie d'une nouvelle version du module, la seule ligne à modifier dans le dkms.conf est en général PACKAGE_VERSION.
MAKE[0] contient la commande à exécuter pour compiler le module, elle peut utiliser de nombreuses variables, listées dans la section suivante. La majorité des modules peuvent se compiler avec la commande suivante : make -C ${kernel_source_dir} SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules
CLEAN contient une commande permettant de nettoyer le répertoire de construction, elle est appelée avant et après la compilation du module.
Les 12 lignes suivantes indiquent les modules générés (ici il y en a 6) et ou il faut les installer. BUILT_MODULE_NAME[i] contient le nom du module numéro i (en commençant à 0) et DEST_MODULE_LOCATION[i] le chemin où installer le module numéro i. Le chemin est relatif à l'arborescence des modules du noyau concerné, /lib/modules/<version du noyau>.
L'option MODULES_CONF_ALIAS_TYPE[0]="eth" indique qu'il faudra ajouter dans /etc/modprobe.conf (ou modules.conf) un alias vers ce module qui s'appelera eth0 (ou eth1, eth2, ... selon ce qui est déjà pris).
REMAKE_INITRD="no" indique que ce pilote n'a pas besoin d'être dans l'initrd. L'initrd est l'image contenant tout les modules et commandes nécessaires pour accéder au disque dur, cette option a donc rarement besoin d'être à yes en dehors des pilotes de contrôleur disque.
AUTOINSTALL="yes" indique que l'on veut que ce module soit compilé et installé automatiquement lorsque l'on démarre sur un nouveau noyau.
Variables disponibles
Quelques variables peut être utilisées dans les options et les commandes comme vous pouvez le voir dans la commande MAKE[0] de l'exemple précédent. Ces variables sont définies par la configuration de DKMS ou par les options passées à la commande dkms.
- $kernelver : Cette variable contient la version du noyau pour laquelle le module est en train d'être construit. C'est particulièrement utile dans la définition de la commande MAKE, par exemple MAKE[0]="make INCLUDEDIR=/lib/modules/${kernelver}/build/include"
- $dkms_tree : Cette variable indique ou se trouve l'arbre DKMS sur le système local. Par défaut il s'agit de /var/lib/dkms, mais cette valeur ne doit pas être mise en dur dans les dkms.conf au cas ou l'utilisateur aurait changé cela sur son système (Un tel réglage se fait à l'aide de /etc/dkms/framework.conf ou en ajoutant l'option --dkmstree lors de l'appel, mais nous ne verrons pas ce genre d'utilisations avancées dans cette article).
- $source_tree : Cette variable indique ou DKMS stocke les sources des modules sur le système. Par défaut il s'agit de /usr/src, mais cette valeur ne doit pas être mise en dur dans les dkms.conf au cas ou l'utilisateur aurait changé cela sur son système (à l'aide de /etc/dkms/framework.conf ou en ajoutant l'option --sourcetree lors de l'appel).
- $kernel_source_dir : Cette variable contient le chemin vers les sources du kernel pour lequel on construit le module. Il s'agit en général de /lib/modules/$kernelver/build, à moins qu'un autre chemin ait été spécifié avec l'option --kernel-sourcedir
Options que l'on peut définir dans le fichier dkms.conf
Tout d'abord, le nom des options est sensible à la casse donc elles doivent être écrites en majuscules. Seules 4 options sont obligatoires :
- PACKAGE_NAME : le nom du package
- PACKAGE_VERSION : la version du package
- BUILT_MODULE_NAME[0] : le nom du module construit. S'il y en a plusieurs, ça sera BUILT_MODULE_NAME[1], BUILT_MODULE_NAME[2], ... Les modules non listés ici ne seront pas installés même s'il sont construit par la commande MAKE[0]
- DEST_MODULE_LOCATION[0] : l'emplacement ou installer le module numéro 0. Ce chemin est relatif au répertoire des modules, et sera par exemple "3rdparty". Il faut renseigner DEST_MODULE_LOCATION[#] pour chaque module listé dans BUILT_MODULE_NAME
De nombreuses autres options bien pratiques mais facultatives dont disponibles :
- MAKE[#] : la commande pour compiler le(s) modules. Voir l'explication de MAKE_MATCH pour la signification du numéro passé en paramètre. Cette option est facultative dans la mesure ou la commande standard de construction d'un module kernel sera utilisée si elle n'est pas définie.
- MAKE_MATCH[#] : cet ensemble d'options permet d'avoir une commande de construction différente en fonction des versions du kernel. Chacune contient une expression régulière qui sera comparée à la version du noyau. Le numéro de la dernière qui correspond indiquera le numéro de commande MAKE à utiliser.
- BUILT_MODULE_LOCATION[#] : le chemin relatif vers le module généré. Cela est nécessaire lorsque le module est généré dans un sous répertoire du répertoire de compilation.
- DEST_MODULE_NAME[#] : le nom a utiliser pour installer le module, s'il y a besoin de le renommer. L'extension (.o ou .ko) ne doit pas être spécifiée. Par défaut le nom original BUILT_MODULE_NAME[#] est conservé.
- MODULES_CONF_ALIAS_TYPE[#] : cette option indique pour chaque module quel alias créer dans /etc/modprobe.conf. DKMS calculera automatiquement le numéro de l'alias en fonction de ceux qui existent déjà. Par exemple si MODULES_CONF_ALIAS_TYPE[0] contient eth et que vous avez déjà eth0 et eth1 définis dans /etc/modprobe.conf, DKMS ajoutera un alias eth2 vers le module. Cette fonctionnalité est à utiliser avec précaution dans la mesure ou elle gère mal les cas complexes, comme par exemple les systèmes avec plusieurs cartes réseau utilisant le même module.
- MODULES_CONF_OBSOLETES[#] : cette option indique à DKMS quels modules vers lesquels pointent des alias dans /etc/modprobe.conf doivent être remplacés par ce nouveau module. Si il y en a plusieurs, les séparer par une virgule. Je pense que ce sera plus clair sur un exemple. Considérons le fichier modprobe.conf suivant :
alias eth0 bcm4400
alias eth1 e1000
Si l'on se contente des options suivantes, DKMS n'a aucun moyen de deviner que b44 et bcm4400 gèrent la même carte et un nouvel alias sera généré.
BUILT_MODULE_NAME[0]="b44"
MODULES_CONF_ALIAS_TYPE[0]="eth"
Le nouveau modprobe.conf contiendra donc :
alias eth0 bcm4400
alias eth1 e1000
alias eth2 b44
Si par contre on ajoute MODULES_CONF_OBSOLETES[0]="bcm4400", le nouveau modprobe.conf sera correct :
alias eth0 b44
alias eth1 e1000
- MODULES_CONF_OBSOLETE_ONLY[#] : Si cette option vaut yes, DKMS ne modifiera modprobe.conf que s'il trouve un alias vers un module obsolète à remplacer. Il n'y aura donc jamais de nouveaux alias de créés.
- STRIP[#] : Par défaut, les symboles de deboguage sont supprimés des modules à l'aide de strip -g. Positionner cette option à "no" pour l'un des modules permet de les conserver dans ce module.
- REMAKE_INITRD : Cette option indique, lorsque la première lettre est y ou Y, qu'il faut régénérer l'initrd après l'installation d'une nouvelle version du module. C'est surtout nécessaire pour les pilotes de contrôleur disque.
- MODULES_CONF[#] : Cette option permet d'indiquer des lignes à ajouter au fichier modprobe.conf. Lorsqu'une première version du module est installée sur l'un des noyaux, les lignes de MODULES_CONF sont ajoutées au fichier modprobe.conf (avant que l'initrd soit régénéré si REMAKE_INITRD est activé). Elles sont supprimées lorsque la dernière version est désinstallée. On peut imaginer par exemple dans le cas de l'ipw2200 MODULES_CONF[0]="options ipw2200 led=1".
- PATCH[#] : Cette option permet d'indiquer des patchs à appliquer sur les sources du pilote avant de le compiler. Tout les patchs doivent se trouver dans /usr/src/<module>-<version du module>/patches/ et sont appliqués avec patch -p1. Vous pouvez spécifier pour quels noyaux chaque patch doit être appliqué en utilisant l'option PATCH_MATCH ci-dessous.
- PATCH_MATCH[#] : Cette option sert à indiquer pour quels noyaux les patchs contenus dans le tableau PATCH doivent être appliqués. PATCH_MATCH[i] contient une expression régulière qui est comparés à la version du noyau cible pour décider si PATCH[i] doit être appliqué.
- AUTOINSTALL : Si cette option vaut "yes", le service dkms (/etc/rc.d/init.d/dkms) essayera automatiquement de construire et installer ce module sur le noyau sur lequel vous démarrez. Ce service ne fera toutefois rien si plusieurs versions du module sont présentes dans l'arbre DKMS, ce sera à vous de décider laquelle vous souhaitez.
- BUILD_EXCLUSIVE_KERNEL : Cette option permet d'indiquer une expression régulière décrivant les versions de noyau pour lesquelles DKMS est autorisé à construire votre module. Si vous essayez de construire le module pour un noyau ne correspondant pas à cette expression régulière, DKMS provoquera une erreur. Par exemple, si vous indiquez "^2.6.*", votre module ne pourra être construit que pour les noyaux 2.6 et une erreur se produira sur les 2.4.
- BUILD_EXCLUSIVE_ARCH : Cette option fonctionne comme BUILD_EXCLUSIVE_KERNEL mais limite l'architecture du noyau au lieu de sa version. Par exemple, si cette option vaut "i.86" votre module pourra être construit pour i386 ou i586 mais pas ppc, x86_64, ni s390.
- POST_ADD : Cette option indique le nom d'un script à exécuter après le traitement de la commande add. Le chemin doit être indiqué relativement aux sources du module.
- POST_BUILD : Cette option indique le nom d'un script à exécuter après le traitement de la commande build. Le chemin doit être indiqué relativement aux sources du module.
- POST_INSTALL : Cette option indique le nom d'un script à exécuter après le traitement de la commande install. Le chemin doit être indiqué relativement aux sources du module.
- POST_REMOVE : Cette option indique le nom d'un script à exécuter après le traitement de la commande remove. Le chemin doit être indiqué relativement aux sources du module.
- PRE_BUILD : Cette option indique le nom d'un script à exécuter avant le traitement de la commande build. Le chemin doit être indiqué relativement aux sources du module.
Intégration avec rpm
Les possibilités d'intégration de DKMS avec RPM sont doubles :
- Création manuelle de RPM contenant les sources et le dkms.conf ;
- Création automatique de rpm contant un module compilé à l'aide de dkms, et dont la gestion est faite par DKMS.
En ce qui concerne le premier cas, la création du RPM est assez simple si vous savez construire des RPM. Vous indiquez comme source le tar.gz des sources du module et dans la section %install vous copiez les sources vers /usr/src/<nom du module>-<version du module> et vous y écrivez le dkms.conf (Il est également possible de mettre le dkms.conf dans un fichier annexe et de l'inclure comme source, mais l'avoir inclus permet d'utiliser les macros RPM %name, %version, ... afin de créer rapidement un .spec pour un nouveau module). Ensuite vous indiquez en %post et %preun les commandes DKMS à invoquer (add, build et install en %post et remove en %preun). Le modèle de fichier spec suivant pourra vous servir de base dans la majorité des cas.
%define module_name rt2500
Name: dkms-%{module_name}
Version: 1.4.6.2
Release: 1mdk
Summary: DKMS-ready kernel-source for the RT2500 driver
License: GPL
URL: http://www.ralinktech.com/supp-1.htm
Source: http://www.ralinktech.com/drivers/Linux/RT2500-Linux-STA-%{version}.tar.bz2
Group: System/Kernel and hardware
Requires(pre): dkms
Requires(post): dkms
Buildroot: %{_tmppath}/%{name}-%{version}-root
Buildarch: noarch
%description
Driver for the Ralink RT2500 802.11g chipset
%prep
%setup -q -n RT2500-Linux-STA-%{version}
chmod 0755 Module/2.*.x
%build
%clean
rm -fr $RPM_BUILD_ROOT
%install
mkdir -p %{buildroot}/usr/src/%{module_name}-%{version}-%{release}
cp -a Module/* %{buildroot}/usr/src/%{module_name}-%{version}-%{release}
cp -af Module/2.6.x/Makefile %{buildroot}/usr/src/%{module_name}-%{version}-%{release}
cat > %{buildroot}/usr/src/%{module_name}-%{version}-%{release}/dkms.conf <<EOF
PACKAGE_VERSION="%{version}-%{release}"
- Items below here should not have to change with each driver version
PACKAGE_NAME="%{module_name}"
MAKE[0]="make -C \${kernel_source_dir} SUBDIRS=\${dkms_tree}/\${PACKAGE_NAME}/\${PACKAGE_VERSION}/build modules"
CLEAN="make -C \${kernel_source_dir} SUBDIRS=\${dkms_tree}/\${PACKAGE_NAME}/\${PACKAGE_VERSION}/build clean"
BUILT_MODULE_NAME[0]="\$PACKAGE_NAME"
DEST_MODULE_LOCATION[0]="/kernel/drivers/net/wireless/"
MODULES_CONF_ALIAS_TYPE[0]="ra"
REMAKE_INITRD="no"
AUTOINSTALL=yes
EOF
%post
dkms add -m %{module_name} -v %{version}-%{release} --rpm_safe_upgrade
dkms build -m %{module_name} -v %{version}-%{release} --rpm_safe_upgrade
dkms install -m %{module_name} -v %{version}-%{release} --rpm_safe_upgrade
%preun
dkms remove -m %{module_name} -v %{version}-%{release} --rpm_safe_upgrade --all ||:
%files
%defattr(-,root,root)
/usr/src/%{module_name}-%{version}-%{release}
Listing 7: Exemple de fichier .spec pour un package DKMS
Il y a peu de remarques à faire sur ce fichier si ce n'est l'importance de ne pas oublier --rpm_safe_upgrade et surtout ||: dans le %preun qui permet que le rpm puisse être désinstallé même si le remove échoue (par exemple parce que le build avait échoué donc le module n'est pas installé).
Pour ce qui est du deuxième cas (création de RPM binaires), c'est encore plus simple, il suffit de compiler le module puis d'utiliser dkms mkrpm en précisant le module, sa version et le ou les noyaux qui vous intéressent. Contrairement aux RPM créés à la main comme précédemment, cette méthode nécessite par contre d'être root sur la machine générant le package (ou d'avoir par exemple un sudo sur la commande dkms).
Avantages et inconvénients
Pour finir, voici une petite liste des avantages et des inconvénients que je vois à utiliser DKMS. Cette liste vous aidera probablement à décider si vous souhaiter essayer de gérer vos pilotes additionnels avec DKMS.
Avantages
- Il n'y a plus besoin de se préoccuper de ses pilotes additionnels lorsque l'on met à jour son noyau ;
- Il est beaucoup plus facile de distribuer des pilotes (y compris les modules propriétaires avec une couche libre de jonction). Avec un seul paquetage à installer l'utilisateur n'a rien à faire pour que ça marche sur son noyau ;
- Il est beaucoup plus facile (et léger) de distribuer des correctifs sur les noyaux. Il n'y a plus besoin de distribuer un nouveau noyau lorsque le problème n'affecte qu'un module, DKMS gérera très bien le remplacement du module original, même si celui-ci n'était initialement pas installé avec DKMS ;
- Il est possible d'avoir plusieurs versions du module présentes sur sa machine simultanément et de basculer entres elles à l'aide de la commande dkms, ce qui est très pratique pour des tests ;
- Il est possible de distribuer le module avec la partie userspace associée plutôt qu'avec le noyau, ce qui permet d'éviter les problèmes de désynchronisation.
Inconvénients
- Le fonctionnement classique de DKMS implique la présence d'un compilateur sur la machine, ce qui est en particulier problématique pour la sécurité des serveurs. Toutefois, DKMS reste utile sans compilateur sur le serveur pour générer depuis une autre machine un RPM contenant la nouvelle version compilée du module et pouvoir ainsi facilement mettre à jour toutes ses machines.
- De même DKMS a besoin des sources du noyau, ce qui occupe beaucoup d'espace disque.
- La recompilation dynamique par un service au démarrage n'est pas adaptée pour les modules nécessaires plus tôt (pilotes de contrôleur disque par exemple), il faut donc dans ce cas s'assurer de faire compiler à DKMS le pilote pour le nouveau noyau avant de redémarrer. Cet inconvénient n'en est toutefois pas réellement un dans la mesure où le problème est le même lorsque le module en question est compilé à la main sans DKMS.
- DKMS est basé sur RPM et ne fonctionnera donc que sur des distributions utilisant RPM (RedHat, Mandriva, SuSE, ...). L'utilisation de rpm est pourtant très localisée (par exemple détection de l'architecture du noyau cible) et il devrait être assez facile de s'en passer.
- DKMS ne prend pour le moment pas en compte le fichier .config du noyau mais celui par défaut fourni par la distribution pour la famille de noyaux (smp, 64G, ...).
Références
- http://linux.dell.com/dkms/dkms.html
- http://www.linuxjournal.com/article/6896
- http://linux.dell.com/dkms/dkms-ols2004.pdf
- http://www.dell.com/downloads/global/power/1q04-ler.pdf
- http://linux.dell.com/dkms/dkms-LWE-Boston2005.pdf
Pascal Terjan <pterjan@mandriva.com> Cet article a été initialement publié dans le GNU/Linux Magazine 80 de Février 2006 Contexte