Cet article décrit un petit projet expérimental sans grande utilité, mais qui a aiguisé ma curiosité pendant quelques temps. Nous allons imbriquer les uns dans les autres des émulateurs de systèmes compilés avec Yocto Project.
Outre le challenge un peu surréaliste que cela représente, nous verrons que cette expérience permet de comprendre certaines dépendances entre packages et d’affiner une recette pour embarquer notre outil Yocto Cooker.
Problématique initiale
Je me suis demandé, il y a quelques années, s’il serait envisageable d’utiliser des cartes ARM bon marché pour créer un cluster de compilation suffisamment puissant pour qu’un build conséquent (une image à créer avec Yocto Project par exemple) s’exécute en un temps sensiblement plus rapide que sur un PC de bureau de milieu de gamme. Les premières expériences que j’avais tentées avec des Raspberry Pi modèle 1B n’étaient pas très concluantes, autant à cause du faible débit réseau de cette carte qu’en raison des limites de son processeur.
J’ai alors assisté à l’occasion de la session 2016 de Kernel Recipes à une présentation fort intéressante de Willy Tarreau qui décrivait une ferme de compilation pour le kernel basée sur des cartes MiQi. Cette présentation a d’ailleurs fait l’objet d’un complément en lighting talk des Kernel Recipes 2017.
Ces conférences sont disponibles sur YouTube :
- Kernel Recipes 2016 – Speeding up development by setting up a kernel build farm – Willy Tarreau (https://www.youtube.com/watch?v=vwQ-KcjskRw)
- Kernel Recipes 2017 – Build farm again – Willy Tarreau (https://www.youtube.com/watch?v=sJwMRA34_SI)
Je n’ai pas vraiment prolongé mes expériences en ce sens, mais c’est un sujet qui continue à m’intéresser. Comme Willy l’indique dans sa conférence, il est indispensable que tous les noeuds utilisent exactement le même compilateur et les mêmes versions de bibliothèque. Il suggère d’utiliser Crosstool-ng pour produire le compilateur. Pour ma part, je préférerais générer une image complète avec Yocto Project ou Buildroot afin de maîtriser entièrement son contenu.
Lorsque je présente des sessions de formation Linux embarqué avec Yocto Project, j’indique qu’une des différences entre une image produite avec Buildroot et une compilée par Yocto est que cette dernière peut facilement inclure un environnement de développement sur la cible.
Cette option est facile à mettre en oeuvre, il suffit d’indiquer
IMAGE_FEATURES += 'tools-sdk'
dans le fichier local.conf
du build. On se retrouve alors avec les outils habituels de développement de la toolchain Gnu (gcc
, g++
, make
, etc.) directement installés sur la cible.
Ceci n’est habituellement pas employé pour un système en production, mais peut néanmoins rendre service dans certains cas pour le développement et la mise au point du code applicatif métier.
Lors d’une session de formation, quelqu’un m’a demandé « Mais alors, on pourrait refaire le build Yocto sur la cible ? » .
Spontanément, j’ai répondu « Dans le principe sûrement, mais en pratique je ne suis pas sûr que tous les outils et bibliothèques nécessaires soient disponibles sous forme de recettes » .
En y réfléchissant un peu plus, je me suis dit qu’a priori rien ne l’interdisait et qu’il serait intéressant d’avoir une liste des packages nécessaires pour qu’une cible soit capable de générer une image Yocto Project.
Sans avoir vraiment d’idée d’application pratique, il me semblait amusant qu’une image soit capable de se répliquer elle-même. J’ai commencé par lister les packages nécessaires pour réaliser cette opération.
Packages de développement nécessaires
Pour pouvoir faire confortablement du développement sur une cible produite par Yocto Project, j’ai sélectionné les packages suivants, présents dans les layers de poky
ou ceux de meta-openembedded
.
bash
,nano
,resolvconf
etssh-server-openssh
pour pouvoir se connecter et travailler sur notre cible un peu plus confortablement qu’avec les outils debusybox
.dev-pkgs
ettools-sdk
nous fournirons une toolchain et les fichiers headers des packages installés.chrpath
,cpio
,git
,perl
,perl-modules
,python3
,rpsvc-proto
,tar
,wget
font partie des outils que l’on installe systématiquement pour travailler avec Yocto Project. Les distributions les intègrent dans des meta-packages commebuild-essential
par exemple.
Depuis bientôt deux ans que nous avons entamé le projet Yocto Cooker avec mon confrère Patrick Boettcher, je n’utilise quasiment plus les composants de Yocto Project (Poky, bitbake
, meta-openembedded
, etc) hors de cooker
.
Il me semblait donc indispensable d’inclure les packages capables de faire fonctionner Yocto Cooker : python3-pkg-resources
, python3-urllib3
et python3-jsonschema
. Il m’a évidemment fallu développer une recette pour intégrer le script cooker
sur la cible.
Cette recette pour cooker
est disponible dans le layer meta-stacking
se trouvant dans le dépôt Git suivant.
# yocto-cooker_1.2.0.bb
SUMMARY = "Yocto Cooker - a meta-buildtool for Yocto Project"
HOMEPAGE = "https://github.com/cpb-/yocto-cooker"
LICENSE = "GPL-2.0"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
inherit pypi setuptools3
SRCREV = "${PV}"
PYPI_PACKAGE = "yocto-cooker"
PYPI_SRC_URI = "git://git@github.com/cpb-/yocto-cooker.git"
S = "${WORKDIR}/git"
RDEPENDS:${PN} += " \
python3-core \
python3-urllib3 \
python3-pkg-resources \
python3-jsonschema \
"
BBCLASSEXTEND = "native"
Recette d’image
Pour regrouper les packages à compiler, j’ai créé une recette d’image afin de pouvoir reproduire facilement le build pour plusieurs architectures.
Cette recette est présente dans le layer meta-stacking
également. Elle s’appelle staking-image.bb
et incorpore les packages indiqués :
# Base image.
inherit core-image
# Comfortable shell and editor.
IMAGE_INSTALL_append = " bash"
IMAGE_INSTALL_append = " nano"
# Network configuration (extended by one of our recipe).
IMAGE_INSTALL_append = " resolv-conf"
# Developpement packages on the target.
IMAGE_FEATURES += "ssh-server-openssh"
IMAGE_FEATURES += "dev-pkgs"
IMAGE_FEATURES += "tools-sdk"
# Yocto Project needed tools.
IMAGE_INSTALL_append = " chrpath"
IMAGE_INSTALL_append = " cpio"
IMAGE_INSTALL_append = " git"
IMAGE_INSTALL_append = " perl"
IMAGE_INSTALL_append = " perl-modules"
IMAGE_INSTALL_append = " python3"
IMAGE_INSTALL_append = " resolvconf"
IMAGE_INSTALL_append = " rpcsvc-proto"
IMAGE_INSTALL_append = " tar"
IMAGE_INSTALL_append = " wget"
# Yocto Cooker needed packages.
IMAGE_INSTALL_append = " yocto-cooker"
IMAGE_INSTALL_append = " python3-pkg-resources"
IMAGE_INSTALL_append = " python3-urllib3"
IMAGE_INSTALL_append = " python3-jsonschema"
Elle contient également une définition d’un utilisateur nommé stack
ayant le mot de passe stack
et autorisé à appeler la commande sudo
.
# A non-priviledged user to run the build.
inherit extrausers
EXTRA_USERS_PARAMS_append = "usermod -P 'root' root;"
EXTRA_USERS_PARAMS_append = "useradd -P 'stack' stack;"
EXTRA_USERS_PARAMS_append = "usermod -a -G sudo stack;"
IMAGE_INSTALL_append = " sudo"
Une petite extension de recette pour sudo
est présente dans le répertoire pour autoriser toutes les actions privilégiées aux utilisateurs du groupe sudo
.
# sudo_%.bbappend
do_install_append () {
install -d -m 0750 ${D}${sysconfdir}/sudoers.d
echo "%sudo ALL=(ALL:ALL) ALL" > ${D}${sysconfdir}/sudoers.d/sudo
chmod 640 ${D}${sysconfdir}/sudoers.d/sudo
}
FILES_${PN} += "${sysconfdir}/sudoers.d/sudo"
Enfin, un package supplémentaire est ajouté dans le fichier d’image, nous en reparlerons plus bas :
IMAGE_INSTALL_append = " kernel-module-tun"
Choix d’une cible
Comme je sentais que j’aurai à repéter plusieurs dizaines de fois le même build en corrigeant certains aspects à chaque fois, j’ai préféré éviter de devoir copier les images sur une cible externe (ou une carte SD) pour tester mon résultat. J’ai donc décidé de travailler avec Qemu.
Le projet Qemu est capable d’émuler de nombreuses machines différentes. Pour ce premier build je vais m’intéresser à une émulation de processeur Arm 64-bits.
Pour rendre le build aisément répétable, je crée un fichier-menu pour Yocto Cooker.
J’incorpore directement le menu dans le dépôt stacking-yocto
décrit plus haut, cela lui évitera de devoir télécharger le menu meta-stacking
qui sera directement présent à côté du menu. Il faudra néanmoins charger les dépôts poky
et meta-openembedded
habituels. Voici donc les sections sources
et layers
du menu :
"sources" : [
{ "url": "git://git.yoctoproject.org/poky", "branch": "dunfell", "rev": "yocto-3.1.13" },
{ "url": "git://git.openembedded.org/meta-openembedded", "branch": "dunfell", "rev": "ab9fca48" }
],
"layers" : [
"poky/meta",
"poky/meta-poky",
"poky/meta-yocto-bsp",
"meta-openembedded/meta-oe",
"meta-openembedded/meta-python",
"meta-stacking"
],
Dans la section builds
je crée une première cible (nous en ajouterons une seconde ensuite) très simple :
"builds" : {
"stacking-arm" : {
"target": "stacking-image",
"local.conf": [
"MACHINE = 'qemuarm64' ",
"IMAGE_ROOTFS_EXTRA_SPACE = '83886080' "
]
}
}
La ligne IMAGE_ROOTFS_EXTRA_SPACE
s’assure que la cible dispose d’un espace libre dans son root filesystem d’au moins 80 Go. Cette valeur est un peu excessive, une cinquantaine aurait largement suffit, mais si on veut faire des builds Yocto, il vaut mieux prévoir large question espace de stockage !
Premier build
Je lance le build, sa durée dépend de la machine de compilation et de l’accès Internet, en général il prend une à deux heures.
$ cooker cook menus/stacking-yocto.json stacking-arm
[...]
Build Configuration:
BB_VERSION = "1.46.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "aarch64-poky-linux"
MACHINE = "qemuarm64"
DISTRO = "poky"
DISTRO_VERSION = "3.1.13"
TUNE_FEATURES = "aarch64 armv8a crc"
TARGET_FPU = ""
meta-oe
meta-python = "HEAD:ab9fca485e13f6f2f9761e1d2810f87c2e4f060a"
meta-stacking = "master:5cf6382098e39cafa2062ebcec98d625a0acfaf5"
meta
meta-poky
meta-yocto-bsp = "HEAD:795339092f87672e4f68e4d3bc4cfd0e252d1831"
[...]
$
Premier lancement
Pour lancer l’émulateur Qemu, je vais utiliser le script runqemu
fourni dans le dépôt poky
. Pour cela, il faut que les variables d’environnement de Poky soient correctement initialisées, et que nous nous placions dans le répertoire de build. C’est le rôle du script oe-init-build-env
que l’on appelle généralement lorsqu’on débute une session de travail pour Yocto.
Ici, nous utilisons Yocto Cooker, aussi vais-je appeler une action spécifique dévolue à ce travail : cooker shell
.
[stacking-yocto]$ cooker shell stacking-arm
[build-stacking-arm]$
Nous pouvons démarrer l’émulateur. Pour pouvoir faire des compilations dans de bonnes conditions, je vais booster un peu la machine émulée en demandant à Qemu de simuler 8 coeurs et de réserver 8 Go de Ram. Bien sûr il faut que le PC sous-jacent soit capable d’offrir ces ressources.
[build-stacking-arm]$ runqemu nographic qemuarm64 qemuparams="-smp cores=8 -m 8192"
[...]
[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x411fd070]
[ 0.000000] Linux version 5.4.158-yocto-standard (oe-user@oe-host) (gcc version 9.3.0 (GCC)) #1 SMP PREEMPT Tue Nov 9 16:43:38 UTC 2021
[ 0.000000] Machine model: linux,dummy-virt
[ 0.000000] Memory limited to 8192MB
[...]
[ 0.050395] smp: Bringing up secondary CPUs ...
[ 0.054475] Detected PIPT I-cache on CPU1
[ 0.055085] CPU1: Booted secondary processor 0x0000000001 [0x411fd070]
[ 0.059503] Detected PIPT I-cache on CPU2
[ 0.059662] CPU2: Booted secondary processor 0x0000000002 [0x411fd070]
[ 0.061141] Detected PIPT I-cache on CPU3
[ 0.061261] CPU3: Booted secondary processor 0x0000000003 [0x411fd070]
[ 0.062670] Detected PIPT I-cache on CPU4
[ 0.062788] CPU4: Booted secondary processor 0x0000000004 [0x411fd070]
[ 0.064316] Detected PIPT I-cache on CPU5
[ 0.064442] CPU5: Booted secondary processor 0x0000000005 [0x411fd070]
[ 0.065838] Detected PIPT I-cache on CPU6
[ 0.065979] CPU6: Booted secondary processor 0x0000000006 [0x411fd070]
[ 0.067396] Detected PIPT I-cache on CPU7
[ 0.067540] CPU7: Booted secondary processor 0x0000000007 [0x411fd070]
[ 0.068284] smp: Brought up 1 node, 8 CPUs
[ 0.068341] SMP: Total of 8 processors activated.
[...]
[ 2.730577] Freeing unused kernel memory: 960K
[ 2.735481] Run /sbin/init as init process
[ 2.806731] usb 1-2: new high-speed USB device number 3 using xhci_hcd
INIT: version 2.96 booting
[ 2.968571] input: QEMU QEMU USB Keyboard as /devices/platform/4010000000.pcie/pci0000:00/0000:00:02.0/usb1/1-2/1-2:1.0/0003:0627:0001.0002/input/input1
[ 3.027371] hid-generic 0003:0627:0001.0002: input: USB HID v1.11 Keyboard [QEMU QEMU USB Keyboard] on usb-0000:00:02.0-2/input0
[ 3.234872] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
Starting udev
[ 3.835170] udevd[146]: starting version 3.2.9
[ 3.908128] udevd[148]: starting eudev-3.2.9
[ 4.356677] EXT4-fs (vda): re-mounted. Opts: (null)
[...]
Poky (Yocto Project Reference Distro) 3.1.13 qemuarm64 ttyAMA0
qemuarm64 login:
Je n’ai conservé que quelques lignes intéressantes du boot du système. Je me trouve donc aux commandes d’une machine dotée d’un processeur ARM 64-bits, émulées dans l’espace utilisateur d’un système tournant sur PC x86-64.
Je peux me connecter et passer quelques commandes pour vérifier ma machine.
qemuarm64 login: stack
Password: (stack)
qemuarm64:~$ lscpu
Architecture: aarch64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 1
Core(s) per socket: 8
Socket(s): 1
Vendor ID: ARM
Model: 0
Model name: Cortex-A57
Stepping: r1p0
BogoMIPS: 125.00
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Spec store bypass: Vulnerable
Vulnerability Spectre v1: Mitigation; __user pointer sanitization
Vulnerability Spectre v2: Vulnerable
Vulnerability Srbds: Not affected
Vulnerability Tsx async abort: Not affected
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
qemuarm64:~$ free
total used free shared buff/cache available
Mem: 8146940 78824 2778852 400 5289264 7972820
Swap: 0 0 0
qemuarm64:~$
Second build
Maintenant que nous sommes dans notre émulateur, nous allons vérifier si notre configuration est suffisante pour re-générer une image équivalente à celle dans laquelle nous évoluons.
Commençons par télécharger le dépôt stacking-yocto
décrit plus haut.
qemuarm64:~$ git clone https://github.com/cpb-/stacking-yocto
qemuarm64:~$ cd stacking-yocto/
Pour varier un peu les plaisirs, j’ai décidé de changer la cible, et de ne plus générer d’image pour émulateur Arm, mais pour émulateur x86.
Le build suivant est ajouté dans le fichier-menu de cooker
:
"stacking-x86" : {
"target": "stacking-image",
"local.conf": [
"MACHINE = 'qemux86-64' ",
"IMAGE_ROOTFS_EXTRA_SPACE = '41943040' "
]
}
J’ai demandé un espace disponible de 40 Go sur le root filesystem de la nouvelle image. En réalité c’est inutile car je ne compte pas relancer un troisième build imbriqué. Toutefois cela me permet de valider que cela soit possible si besoin.
Je lance alors la compilation. Attention, celle-ci dure beaucoup plus longtemps que la précédente. Sur mon poste de travail, le premier build a duré environ 1 heure et celui-ci 34 heures !
Il faut bien comprendre qu’avec Qemu, nous ne sommes pas dans la même situation qu’avec des outils comme Virtual Box ou Vmware qui nous offrent un PC virtuel dans un PC réel en tirant parti des spécificité du processeur mais en restant sur la même architecture.
Ici, nous avons une machine basée sur un processeur ARM qui fonctionne dans une machine basée sur processeur x86. Cela nécessite beaucoup plus de travail de traduction d’instructions et de simulation de matériel.
qemuarm64:~/stacking-yocto$ cooker cook menus/stacking-yocto.json stacking-x86
# Update layers in project directory
# Downloading source from git://git.yoctoproject.org/poky
# Updating source /home/stack/stacking-yocto/layers/poky...
# Downloading source from git://git.openembedded.org/meta-openembedded
# Updating source /home/stack/stacking-yocto/layers/meta-openembedded...
# Generating dirs for all build-configurations
# Building stacking-x86 (stacking-image)
[...]
NOTE: Tasks Summary: Attempted 5081 tasks of which 8 didn't need to be rerun and all succeeded.
Summary: There was 1 WARNING message shown.
qemuarm64:~/stacking-yocto$
Second lancement
Une fois le long build terminé, nous allons vais lancer l’émulateur qemux86-64
à l’intérieur de l’émulation qemuarm-64
.
Comme le script runqemu
essayer d’établir un bridge avec l’interface tun
, il faut charger ce module dans le noyau. C’est pour cela que j’avais ajouté le package kernel-module-tun
dans l’image.
qemuarm64:~/stacking-yocto$ sudo /sbin/modprobe tun
Password: (stack)
[126823.002017] tun: Universal TUN/TAP device driver, 1.6
qemuarm64:~/stacking-yocto$
Pour lancer runqemu
, je vais procéder comme au niveau précédent, en appelant cooker shell
pour préparer les variables d’environnement nécessaires.
qemuarm64:~/stacking-yocto$ cooker shell stacking-x86
sh-5.0$
Il me faut ajouter dans la variable PATH
le chemin /sbin/
pour que le script puisse trouver la commande ip
sh-5.0$ PATH=$PATH:/sbin/ sh-5.0$ sudo runqemu nographic qemux86-64 runqemu - INFO - Running MACHINE=qemux86-64 bitbake -e ...
Prenons un instant de recul pour assimiler la situation :
La machine de base (la plus externe sur le schéma ci-contre) est un PC de type X86 64-bits dont les ressources sont gérées par le noyau Linux fourni par une distribution classique.
Dans l’espace utilisateur de ce PC nous faisons fonctionner l’application Qemu qui simule un processeur Arm 64-bits et tous les périphériques nécessaires.
Dans cette seconde machine nous chargeons un noyau Linux et un espace applicatif fournis par l’image Yocto produite sur le PC. Sur cet environnment Arm-64 émulé, nous avons, dans un premier temps, utilisé les outils embarqués par Yocto pour générer une seconde image.
Dans l’espace utlisateur de la machine Arm 64-bits, nous exécutons de nouveau Qemu, pour simuler cette fois un processeur x86 64-bits.
Le démarrage du kernel de ce troisième système dure assez longtemps, mais il nous fournit un accès à la machine interne, et nous pourrions en théorie continuer à imbriquer des systèmes les uns dans les autres, avec la seule limite de la taille mémoire et de l’espace disque disponibles.
Cette fois le boot dure beaucoup plus longtemps que précédemment (environ une heure de boot, ça m’a rappelé une mise à jour du système HP-9000 de mon école que nous avions dû faire lorsque j’étais étudiant).
Durant le boot, il y a plusieurs notification d’erreur de timers hpet
mais il progresse quand même.
En voici, quelques lignes représentatives, ainsi que ma connexion dans la nouvelle machine émulée et quelques commandes.
[ 0.000000] Linux version 5.4.158-yocto-standard (oe-user@oe-host) (gcc version 9.3.0 (GCC)) #1 SMP PREEMPT Tue N1 [ 0.000000] Command line: root=/dev/vda rw console=ttyS0 mem=256M ip=192.168.7.2::192.168.7.1:255.255.255.0 opro [ 0.000000] x86/fpu: x87 FPU will use FXSAVE [ 0.000000] BIOS-provided physical RAM map: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000000ffdafff] usable [ 0.000000] BIOS-e820: [mem 0x000000000ffdb000-0x000000000fffffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved [...] [ 91.949907] EXT4-fs (vda): mounted filesystem with ordered data mode. Opts: (null) [ 91.972343] VFS: Mounted root (ext4 filesystem) on device 253:0. [ 92.076125] devtmpfs: mounted [ 93.985423] Freeing unused kernel image memory: 1592K [ 94.019320] Write protecting the kernel read-only data: 20480k [ 94.133314] Freeing unused kernel image memory: 2004K [ 94.164625] Freeing unused kernel image memory: 908K [ 94.184161] Run /sbin/init as init process INIT: version 2.96 booting Starting udev [...] Poky (Yocto Project Reference Distro) 3.1.13 qemux86-64 ttyS0 qemux86-64 login: stack Password: (stack) qemux86-64:~$ uname -a Linux qemux86-64 5.4.158-yocto-standard #1 SMP PREEMPT Tue Nov 9 16:42:29 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux qemux86-64:~$ free total used free shared buff/cache available Mem: 236708 30204 165348 264 41156 197720 Swap: 0 0 0 qemux86-64:~$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 40 bits physical, 48 bits virtual CPU(s): 1 On-line CPU(s) list: 0 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 15 Model name: Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz Stepping: 11 CPU MHz: 999.564 BogoMIPS: 1999.12 L1d cache: 32 KiB L1i cache: 32 KiB L2 cache: 4 MiB L3 cache: 16 MiB Vulnerability Itlb multihit: Processor vulnerable Vulnerability L1tf: Mitigation; PTE Inversion Vulnerability Mds: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Vulnerability Meltdown: Mitigation; PTI Vulnerability Spec store bypass: Vulnerable Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Full generic retpoline, STIBP disabled, RSB filling Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected Flags: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush acpi mmx fxsr sse sse2 syscall nx lm constant_tsc rep_good nopl cpuid pni monitor ssse3 cx16 hypervisor lahf_lm pti qemux86-64:~$ /sbin/ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 pfifo_fast state UP group default qlen 1000 link/ether 52:54:00:12:34:02 brd ff:ff:ff:ff:ff:ff inet 192.168.7.2/24 brd 192.168.7.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:fe12:3402/64 scope link valid_lft forever preferred_lft forever 3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000 link/sit 0.0.0.0 brd 0.0.0.0
Si nous essayons d’utiliser le réseau depuis la machine la plus interne, cela ne fonctionne pas. Pour comprendre pourquoi, nous pouvons nous connecter en SSH sur la machine intermédiaire depuis le PC :
[~]$ ssh stack@192.168.7.2
stack@192.168.7.2's password: (stack)
qemuarm64:~$ /sbin/ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:12:34:02 brd ff:ff:ff:ff:ff:ff
inet 192.168.7.2/24 brd 192.168.7.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe12:3402/64 scope link
valid_lft forever preferred_lft forever
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/sit 0.0.0.0 brd 0.0.0.0
4: tap0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 92:30:d5:fa:5e:c6 brd ff:ff:ff:ff:ff:ff
qemuarm64:~$
Un petit inconvénient apparaît ici : Qemu utilise le sous-réseau 192.168.7.0/24
sur l’interface eth0
qu’il simule entre la machine intermédiaire et le PC.
Lorsqu’on démarre la seconde émulation imbriquée, Qemu essaye d’utiliser le même sous-réseau sur l’interface tap0
qui sert à accéder à la machine la plus interne. Le routage échoue et la machine interne n’a pas accès au réseau externe. Il faudrait demander à Qemu de changer de sous-réseau, mais je n’ai pas eu le courage de relancer le boot (qui dure une heure) de la seconde émulation.
Après quelques minutes, j’arrête la machine la plus interne, et je retourne sur l’émulateur intermédiaire (la commande halt
ne prend pas autant de temps que le boot, mais il faut quand même un peu de patience).
qemux86-64:~$ sudo /sbin/halt Broadcast message from root@qemux86-64 (ttyS0) (Wed Feb 2 13:54:19 2022): The system is going down for system halt NOW! INIT: Switching to runlevel: 0 INIT: Sending processes configured via /etc/inittab the TERM signal Stopping OpenBSD Secure Shell server: sshdstopped /usr/sbin/sshd (pid 324) . * Stopping Avahi mDNS/DNS-SD Daemon: avahi-daemon *iled to kill daemon: Timer expired ] Stopping bluetooth: bluetoothd. Stopping system message bus: dbus. stopping mountd: done stopping nfsd: [14043.507768] nfsd: last server has exited, flushing export cache done Stopping syslogd/klogd: stopped syslogd (pid 374) stopped klogd (pid 377) [...] Sending all processes the TERM signal... logout Sending all processes the KILL signal... Unmounting remote filesystems... Deactivating swap... Unmounting local filesystems... [14411.850884] EXT4-fs (vda): re-mounted. Opts: (null) [14449.613391] ACPI: Preparing to enter system sleep state S5 [14449.765252] reboot: Power down runqemu - INFO - Cleaning up sh-5.0$
Nous voici de retour dans l’émulateur intermédiaire, j’en profite pour voir le volume de root filesystem qui a été utilisé par le build Yocto Project :
sh-5.0$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 78822416 58268392 16305412 79% / devtmpfs 4072988 0 4072988 0% /dev tmpfs 4073468 108 4073360 1% /run tmpfs 4073468 328 4073140 1% /var/volatile sh-5.0$
Un peu moins de 60 Go sont occupés pour stocker le système lui-même, ainsi que les sources et les fichiers binaires produits par la compilation. Je termine en arrêtant cet émulateur pour revenir sur mon shell (fourni par Yocto Cooker) du PC.
sh-5.0$ sudo /sbin/halt Password: (stack) Broadcast message from root@qemuarm64 (ttyAMA0) (Wed Feb 2 14:18:36 2022): The system is going down for system halt NOW! INIT: Switching to runlevel: 0 [...] Set 'tap0' nonpersistent [build-stacking-arm]$ exit exit [stacking-yocto]$
Conclusion
Finalement nous nous sommes éloignés de l’idée initiale qui avait motivé cette série d’expérimentations, et qui concernait plutôt les fermes de build et la compilation distribuée.
Néanmoins, même si cette expérience n’est pas très utile en pratique, j’en conviens volontiers, elle nous a permis d’établir la liste des packages nécessaires pour mener à bien une compilation d’une image avec Yocto Project. En outre j’ai pu en profiter pour rédiger la recette servant à embarquer Yocto Cooker.
Notons quand même que cette série de compilations nous permet de valider le fait qu’une image produite avec Yocto Project (et avec les layers de meta-openembedded
) peut être auto-suffisante et peut embarquer tous les outils nécessaires pour se regénérer intégralement.