Imbriquer des systèmes Linux avec Yocto Cooker

Publié par cpb
Fév 03 2022

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 :

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 et ssh-server-openssh pour pouvoir se connecter et travailler sur notre cible un peu plus confortablement qu’avec les outils de busybox.
  • dev-pkgs et tools-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 comme build-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.

URL de trackback pour cette page