La configuration du système que nous avons réalisée jusqu'ici était relativement simple :
Nous pouvons néanmoins avoir besoin de réaliser une configuration plus approfondie du système, c'est ce que nous évoquerons dans cette séquence.
Pour cette séquence, et les suivantes je vais repartir d'une image personnalisée en utilisant comme cible un Raspberry Pi 4. Je souhaite éviter l'émulation par QEmu pour disposer d'une vraie connexion réseau Ethernet. En outre le Raspberry Pi ne dispose pas de RTC (Real Time Clock) ce qui nous donnera l'occasion de gérer explicitement la mise à l'heure.
[Yocto-lab]$ source layers/poky/oe-init-build-env builds/build-rpi/ [build-rpi]$
J'utilise donc un fichier conf/local.conf
dans lequel les lignes
suivantes ont été ajoutées
# <LOGILIN> MACHINE="raspberrypi4" LICENSE_FLAGS_ACCEPTED += 'synaptics-killswitch' DL_DIR="${TOPDIR}/../downloads" SSTATE_DIR="${TOPDIR}/../sstate-cache" ENABLE_UART="1" INHERIT += "extrausers" EXTRA_USERS_PARAMS += "useradd -p '\$5\$gFkqOeNU\$BOtEK2RhJIu.MxFT4jqtaYGYdw85fiRbc4hplRWI/63' guest;" EXTRA_USERS_PARAMS += "usermod -p '\$5\$IlhPmUHu\$AFPAiidalJ5Llt5YSqKoKXUbiWJjbvtRYT0AvzJp6p7' root;" hostname:pn-base-files = "mybox" DISTRO = "my-distro" # </LOGILIN> [...]
J'ajoute deux layers que nous n'avions pas utilisé dans le build pour Raspberry Pi jusqu'à présent.
[build-rpi]$ bitbake-layers add-layer ../../layers/meta-my-layer/ NOTE: Starting bitbake server... [build-rpi]$ bitbake-layers add-layer ../../layers/meta-openembedded/meta-oe/ NOTE: Starting bitbake server... [build-rpi]$
Enfin, notre
fichier ../../layers/meta-my-layer/recipes-custom/images/my-image.bb
est configuré comme suit :
SUMMARY = "A customized image for development purposes." LICENSE = "MIT" inherit core-image IMAGE_FEATURES += "splash" IMAGE_FEATURES += "tools-debug" IMAGE_FEATURES += "tools-profile" IMAGE_FEATURES += "tools-sdk" IMAGE_FEATURES += "ssh-server-dropbear" IMAGE_FEATURES += "read-only-rootfs" IMAGE_INSTALL:append = " mc" IMAGE_INSTALL:append = " nano" IMAGE_INSTALL:append = " my-scripts" IMAGE_INSTALL:append = " python3-modules" IMAGE_INSTALL:append = " python-hello" IMAGE_INSTALL:append = " hello-autotools" IMAGE_INSTALL:append = " hello-cmake" IMAGE_INSTALL:append = " hello-makefile" IMAGE_INSTALL:append = " hello-simple"
Je dois souvent répéter pour des clients des configurations comme celle-ci, c'est à dire :
conf/local.conf
»,Dans ce cas, j'utilise l'outil Yocto Cooker que je vous présente dans une série de trois articles.
J'ai relancé un build (qui a duré un moment car la dernière image pour Raspberry Pi datait de la séquence I.3).
[build-rpi]$ bitbake my-image
Notre image étant compilée et installée sur une carte micro-SD, nous pouvons démarrer le Raspberry Pi.
My experimental distro 1.0 mybox ttyS0 mybox login: root Password: (linux) root@mybox:~# uname -a Linux mybox 6.6.22-v7l #1 SMP Tue Mar 19 17:41:59 UTC 2024 armv7l GNU/Linux root@mybox:~# cat /sys/firmware/devicetree/base/model Raspberry Pi 4 Model B Rev 1.5
Au démarrage nous voyons ces traces qui ressemblent à des messages d'erreur :
udhcpc: started, v1.36.1 udhcpc: broadcasting discover udhcpc: broadcasting discover udhcpc: broadcasting discover udhcpc: no lease, forking to background
Par défaut, Yocto nous propose une image dont la configuration réseau est dynamiquement obtenue à l'aide du protocole DHCP.
Plus précisément, le Raspberry Pi envoie sur le réseau Ethernet un message broadcast disant «Mon adresse matérielle est XX:XX:XX:XX:XX, je souhaite obtenir une adresse IP». Normalement un serveur DHCP présent sur le réseau (généralement un routeur pour les réseaux d'entreprise ou une box dans un cadre domestique) lui répond en lui indiquant entre autres l'adresse IP qui lui est attribuée, l'adresse de la passerelle de sortie du sous-réseau et l'adresse du serveur DNS permettant de traduire les URL en adresse IP.
Mon Raspberry Pi n'était pas relié au réseau, nous voyons donc les messages d'échec de l'initialisation. Si je branche son port Ethernet sur le réseau local et que je le redémarre, les messages sont différents :
udhcpc: started, v1.36.1 udhcpc: broadcasting discover udhcpc: broadcasting discover [ 16.247216] bcmgenet fd580000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx udhcpc: broadcasting discover udhcpc: broadcasting select for 192.168.3.46, server 192.168.3.254 udhcpc: lease of 192.168.3.46 obtained from 192.168.3.254, lease time 43200
Une fois connecté, je peux vérifier la configuration réseau.
My experimental distro 1.0 mybox ttyS0 mybox login: root Password: (linux) root@mybox:~# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000 link/ether e4:5f:01:ba:ac:61 brd ff:ff:ff:ff:ff:ff inet 192.168.3.46/24 brd 192.168.3.255 scope global eth0 valid_lft forever preferred_lft forever inet6 2a01:e0a:22:ea90:e65f:1ff:feba:ac61/64 scope global dynamic flags 100 valid_lft 86363sec preferred_lft 86363sec inet6 fe80::e65f:1ff:feba:ac61/64 scope link valid_lft forever preferred_lft forever 3: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000 link/ether e4:5f:01:ba:ac:62 brd ff:ff:ff:ff:ff:ff root@mybox:~#
Il existe toutefois de nombreuses situations où on ne dispose pas de serveur DHCP sur notre réseau, et ceci pour différentes raisons (sécurité, politique d'administration, réseau industriel dédié à certains équipements…).
Nous pouvons modifier la configuration de Yocto pour que notre système dispose d'une configuration réseau statique avec des adresses fixées dès la production de l'image.
Pour cela, il nous faut configurer le fichier
/etc/network/interfaces
de la cible. Par défaut son
contenu est le suivant
root@mybox:~# cat /etc/network/interfaces # /etc/network/interfaces -- configuration file for ifup(8), ifdown(8) # The loopback interface auto lo iface lo inet loopback # Wireless interfaces iface wlan0 inet dhcp wireless_mode managed wireless_essid any wpa-driver wext wpa-conf /etc/wpa_supplicant.conf iface atml0 inet dhcp # Wired or wireless interfaces including predictable names auto eth0 iface eth0 inet dhcp iface eth1 inet dhcp # Busybox ifupdown won't process /en* correctly auto /en*=eth iface eth inet dhcp # Ethernet/RNDIS gadget (g_ether) # ... or on host side, usbnet and random hwaddr iface usb0 inet static address 192.168.7.2 netmask 255.255.255.0 network 192.168.7.0 gateway 192.168.7.1 # Bluetooth networking iface bnep0 inet dhcp
Le moins que l'on puisse dire, c'est que la gamme des interfaces gérées par ce fichier est plutôt large :
lo
»
est initialisée dès
le démarrage (mot-clé «auto
»). Il
s'agit d'une interface IP (mot-clé
«inet
») fonctionnant en
loopback (pour les communications internes au système).
wlan0
»
n'est pas activée au démaraage, mais elle est
configurée en poste client prêt à se connecter aux réseaux
décrits dans le fichier /etc/wpa_supplicant.conf
.
Son adressage IP est obtenu dynamiquement (mot-clé
«dhcp
»).
atml0
» (sans fil
Atmel) et les deux interfaces Ethernet
«eth0
» et
«eth1
» sont aussi configurées par le
protocole DHCP. Seule l'interface eth0
est activée
automatiquement au démarrage.
usb0
»
est configurée statiquement : lorsqu'un hôte est relié par
un câble USB à notre cible (qu'il voit comme un périphérique
— device — USB), celle-ci initialise une
communication réseau et prend l'adresse IP
192.168.7.2
. Cette configuration est normalement
associée à la présence d'un serveur DHCP qui affecte à l'hôte
l'adresse 192.168.7.1
.
bnep0
»
est également prête à recevoir une configuration dynamique par DHCP.
Ce fichier est très riche, mais en pratique son contenu utile est beaucoup plus réduit :
atml0
»,
ni «eth1
» ni port USB device
permettant d'utiliser «usb0
» (ses
ports USB sont uniquement hosts).
bnep0
» n'est pas
utilisable sans le chargement de modules (et d'overlays
pour le device tree) spécifiques.
wlan0
» nécessite une
configuration supplémentaire pour connaître les identifiants
des réseaux auxquels se connecter.
Il nous reste au final deux interfaces utilisables
immédiatement après le boot : «lo
» et
«eth0
». Pour avoir une configuration statique
de notre interface Ethernet, il suffirait donc que
notre fichier /etc/network/interfaces
ressemble à :
auto lo iface lo inet loopback auto eth0 iface eth0 inet static address 192.168.3.101 netmask 255.255.255.0 gateway 192.168.3.254 dns-nameserver 8.8.8.8
La configuration du réseau Ethernet est évidement à adapter en fonction
des situations. La ligne «address
» configure
l'adresse IP du Raspberry Pi, la ligne
«netmask
» le masque binaire du sous-réseau et
celle «gateway
» l'adresse de la passerelle à
joindre pour accéder aux autres sous-réseaux et à Internet.
Une ligne est moins habituelle :
«dns-nameserver
»
permet d'indiquer un serveur
DNS, toutefois cette option ne fonctionne pas encore sur notre
Raspberry Pi, car il manque un package dans notre image.
Si nous modifions manuellement le fichier interfaces
de la
cible et redémarrons, nous pouvons observer la configuration
suivante :
My experimental distro 1.0 mybox ttyS0 mybox login: root Password: (linux) root@mybox:~# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000 link/ether e4:5f:01:ba:ac:61 brd ff:ff:ff:ff:ff:ff inet 192.168.3.101/24 scope global eth0 valid_lft forever preferred_lft forever inet6 2a01:e0a:22:ea90:e65f:1ff:feba:ac61/64 scope global dynamic flags 100 valid_lft 86331sec preferred_lft 86331sec inet6 fe80::e65f:1ff:feba:ac61/64 scope link valid_lft forever preferred_lft forever 3: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000 link/ether e4:5f:01:ba:ac:62 brd ff:ff:ff:ff:ff:ff root@mybox:~# ip route default via 192.168.3.254 dev eth0 192.168.3.0/24 dev eth0 scope link src 192.168.3.101 root@mybox:~# ping 192.168.3.254 PING 192.168.3.254 (192.168.3.254): 56 data bytes 64 bytes from 192.168.3.254: seq=0 ttl=64 time=0.376 ms 64 bytes from 192.168.3.254: seq=1 ttl=64 time=0.315 ms 64 bytes from 192.168.3.254: seq=2 ttl=64 time=0.284 ms ^C --- 192.168.3.254 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.284/0.325/0.376 ms
L'adresse IP de l'interface eth0
est correcte, et on
arrive à joindre une autre adresse du même sous-réseau (ici la
passerelle). Essayons de joindre une adresse IP distante sur
Internet :
root@mybox:~# ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: seq=0 ttl=119 time=4.141 ms 64 bytes from 8.8.8.8: seq=1 ttl=119 time=3.819 ms 64 bytes from 8.8.8.8: seq=2 ttl=119 time=3.481 ms 64 bytes from 8.8.8.8: seq=3 ttl=119 time=3.340 ms ^C --- 8.8.8.8 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 3.340/3.695/4.141 ms
Ce serveur DNS de Google est bien accessible. Essayons de résoudre une adresse symbolique
root@mybox:~# ping www.kernel.org ping: bad address 'www.kernel.org' root@mybox:~#
La résolution de noms échoue, car il nous manque le package
«resolvconf
» qui prend en compte la ligne
«dns-nameservers
» du fichier
interfaces
.
Nous pouvons commencer par rajouter la ligne suivante dans notre
fichier d'image :
IMAGE_INSTALL:append = " resolvconf"
Toutefois, cela n'est pas suffisant. Nous avons modifié le fichier
interfaces
directement sur la cible, mais nous souhaitons
qu'il soit configuré comme nous le voulons dès la production de
l'image. Nous devons donc rechercher quelle recette le fournit.
Un problème revient régulièrement lorsque l'on cherche à affiner la
configuration d'une image produite par Yocto Project : «mais
quelle recette a bien pu installer ce fichier ?». Profitons
de l'occasion offerte par le fichier
«interfaces
» pour voir comment procéder.
Nous allons employer l'outil devtool
pour qu'il nous indique quelle recette installe le
fichier indiqué. La commande est exécutée sur la machine de
développement, mais le chemin passé en argument correspond à celui
observé dans l'arborescence de la cible :
[build-rpi]$ devtool search /etc/network/interface NOTE: Starting bitbake server... recommended that you use a tested distribution. Loading cache: 100% |###################################################################################################| Time: 0:00:00 Loaded 3259 entries from dependency cache. Summary: There was 1 WARNING message. init-ifupdown Basic TCP/IP networking init scripts and configuration files
Le nom du package est indiqué sur la dernière ligne :
«init-ifupdown
». Nous pouvons aussi demander
à devtool
de rechercher l'emplacement de la recette en
question (même s'il est assez évident que c'est une recette de base de
Poky) :
[build-rpi]$ devtool find-recipe init-ifupdown NOTE: Starting bitbake server... INFO: Creating workspace layer in /home/Builds/Lab/builds/build-rpi/workspace Loading cache: 100% | | ETA: --:--:-- Loaded 0 entries from dependency cache. Parsing recipes: 100% |#################################################################################################| Time: 0:00:29 Parsing of 1921 .bb files complete (0 cached, 1921 parsed). 3259 targets, 135 skipped, 0 masked, 0 errors. Summary: There was 1 WARNING message. /home/Builds/Lab/layers/poky/meta/recipes-core/init-ifupdown/init-ifupdown_1.0.bb
Voyons le contenu du répertoire de cette recette :
[build-rpi]$ ls ../../layers/poky/meta/recipes-core/init-ifupdown/ init-ifupdown-1.0 init-ifupdown_1.0.bb [build-rpi]$ ls ../../layers/poky/meta/recipes-core/init-ifupdown/init-ifupdown-1.0/ copyright init interfaces nfsroot qemuall [build-rpi]$
Le fichier «interfaces
» est bien là ! Il
ne nous reste plus qu'à le remplacer en suivant la même méthode que
celle que nous avions employée dans
la
séquence II.3. Commençons par créer les répertoires nécessaires
dans notre layer :
[build-rpi]$ mkdir -p ../../layers/meta-my-layer/recipes-core/init-ifupdown/init-ifupdown/
Puis nous y copions le fichier
«interfaces
» présenté plus-haut :
[build-rpi]$ nano ../../layers/meta-my-layer/recipes-core/init-ifupdown/init-ifupdown/interfaces auto lo iface lo inet loopback auto eth0 iface eth0 inet static address 192.168.3.101 netmask 255.255.255.0 gateway 192.168.3.254 dns-nameserver 8.8.8.8
Et enfin nous écrivons une petite extension .bbappend
pour
indiquer que les fichiers concernant cette recette doivent être
recherchés en priorité dans notre sous-répertoire :
[build-rpi]$ nano ../../layers/meta-my-layer/recipes-core/init-ifupdown/init-ifupdown_%.bbappend FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
Nous pouvons relancer le build et réinstaller notre image sur la carte SD du Raspberry Pi. Une fois le boot terminé, nous observons :
My experimental distro 1.0 mybox ttyS0 mybox login: root Password: (linux) root@mybox:~# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000 link/ether e4:5f:01:ba:ac:61 brd ff:ff:ff:ff:ff:ff inet 192.168.3.46/24 brd 192.168.3.255 scope global eth0 valid_lft forever preferred_lft forever inet6 2a01:e0a:22:ea90:e65f:1ff:feba:ac61/64 scope global dynamic flags 100 valid_lft 86397sec preferred_lft 86397sec inet6 fe80::e65f:1ff:feba:ac61/64 scope link valid_lft forever preferred_lft forever 3: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000 link/ether e4:5f:01:ba:ac:62 brd ff:ff:ff:ff:ff:ff root@mybox:~# ping www.kernel.org PING www.kernel.org (145.40.68.75): 56 data bytes 64 bytes from 145.40.68.75: seq=0 ttl=52 time=10.495 ms 64 bytes from 145.40.68.75: seq=1 ttl=52 time=11.443 ms 64 bytes from 145.40.68.75: seq=2 ttl=52 time=10.852 ms ^C --- www.kernel.org ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 10.495/10.930/11.443 ms root@mybox:~#
La configuration est bien celle que nous avons fixée statiquement, la résolution de noms fonctionne ainsi que la communication avec une machine distante sur Internet.
Cette séquence nous a permis de personnaliser la configuration réseau, mais au-delà de cette action, nous avons vu comment expérimenter directement sur la cible et reporter ensuite les modifications dans l'image en recherchant les recettes concernées et en les surchargeant.
Si vous préférez une session de cours interactif, en mode présentiel ou distanciel, n'hésitez pas à vous inscrire à mes formations "Développeur Linux embarqué avec Yocto Project" ou "Yocto Project avancé" .
Ce document est placé sous licence Creative Commons CC BY-NC. Vous pouvez copier son contenu et le réemployer à votre gré pour une utilisation non-commerciale. Vous devez en outre mentionner sa provenance.
Le nom Yocto Project est une marque déposée par la Linux Foundation. Le présent document n'est en aucune façon approuvé par Yocto Project ou la Linux Foundation.