Par Pascal.
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é.
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.
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 :
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 le système DKMS
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 :
o Les répertoire ou seront construits 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.
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.
Nous allons maintenant étudier ce que permet de faire DKMS à travers le parcours des actions que l'on peut faire effectuer à la commande dkms.
[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.
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.
------------------------------ Deleting module version: 0.9.0 completely from the DKMS tree. ------------------------------Done.
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.
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.
[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.
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.
[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: builtsysprof, 1.0, 2.6.12-12mdk-i686-up-4GB, i586: installed
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.gzDKMS: mktarball Completed.
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.
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.
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.0dkms 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.
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.
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/d rivers/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.
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.
Tout d'abord, le nom des options est sensible à la casse donc elles doivent être écrites en majuscules. Seules 4 options sont obligatoires :
De nombreuses autres options bien pratiques mais facultatives dont disponibles :
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é.
Le nouveau modprobe.conf contiendra donc :
alias eth1 e1000
alias eth2 b44Si par contre on ajoute MODULES_CONF_OBSOLETES[0]="bcm4400", le nouveau modprobe.conf sera correct :
Les possibilités d'intégration de DKMS avec RPM sont doubles :
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).
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.
@ Retour à la rubrique Noyau et modules
Pascal Terjan <pterjan at mandriva dot com>
Cet article a été initialement publié dans le GNU/Linux Magazine 80 de Février 2006.
© 2006 Pascal Terjan
Vous avez l'autorisation de copier, distribuer et/ou modifier ce document suivant les termes de la Licence pour documents libres, Version 1.1 publiée par la La Guilde des Doctorants. Pour plus d'informations consulter la LDL sur le site de La Guilde des Doctorants. |