«« sommaire »»

IV.1 – Configuration du réseau

Christophe BLAESS - juillet 2024

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.

Configuration de référence

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 :

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

Configuration initiale du réseau

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 :

Ce fichier est très riche, mais en pratique son contenu utile est beaucoup plus réduit :

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.

Configuration réseau statique

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.

Recherche de la recette responsable d'un fichier

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.

Conclusion

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.

«« sommaire »»