Merge pull request #1090 from kernelkit/doc

doc: minor markdownlint cleanup and fixes to admonitions
This commit is contained in:
Joachim Wiberg
2025-08-08 15:22:19 +02:00
committed by GitHub
6 changed files with 455 additions and 403 deletions
+137 -136
View File
@@ -1,37 +1,36 @@
Boot Procedure # Boot Procedure
==============
Systems running Infix will typically boot in multiple phases, forming Systems running Infix will typically boot in multiple phases, forming
a boot chain. Each link in the chain has three main responsibilities: a boot chain. Each link in the chain has three main responsibilities:
1. Ensuring the integrity of the next link before passing control to 1. Ensuring the integrity of the next link before passing control to
it. This avoids silent failures stemming from data corruption. it. This avoids silent failures stemming from data corruption.
1. Ensuring the authenticity of the next link before passing control
2. Ensuring the authenticity of the next link before passing control
to it, commonly referred to as _Secure Boot_. This protects against to it, commonly referred to as _Secure Boot_. This protects against
malicious attempts to modify a system's firmware. malicious attempts to modify a system's firmware.
1. Preparing the system state according to the requirements of the
3. Preparing the system state according to the requirements of the
next link. E.g. the Linux kernel requires the system's RAM to be next link. E.g. the Linux kernel requires the system's RAM to be
operational. operational.
A typical chain consists of four stages: A typical chain consists of four stages:
.---------. ```
| ROM >---. Determine the location of and load the SPL .---------.
'---------' | | ROM >---. Determine the location of and load the SPL
.-----------------' '---------' |
| .---------. .-----------------'
'---> SPL >---. Perform DDR training and load the TPL | .---------.
'---------' | '---> SPL >---. Perform DDR training and load the TPL
.-----------------' '---------' |
| .---------. .-----------------'
'---> TPL >---. Load Linux kernel, device tree, and root filesystem | .---------.
'---------' | '---> TPL >---. Load Linux kernel, device tree, and root filesystem
.-----------------' '---------' |
| .---------. .-----------------'
'---> Infix | Get down to business | .---------.
'---------' '---> Infix | Get down to business
'---------'
```
After a reset, hardware will pass control to a program (_ROM_) which After a reset, hardware will pass control to a program (_ROM_) which
is almost always programmed into the SoC by the vendor. This program is almost always programmed into the SoC by the vendor. This program
@@ -52,9 +51,7 @@ This document's focus is to describe the final two phases of the boot
chain, as the initial phases are very hardware dependent, better chain, as the initial phases are very hardware dependent, better
described by existing documentation provided by the SoC vendor. described by existing documentation provided by the SoC vendor.
## Bootloader
Bootloader
----------
### Configuration ### Configuration
@@ -62,33 +59,42 @@ To mitigate the risk of a malicious user being able to circumvent the
bootloader's validation procedure, user configuration is kept to a bootloader's validation procedure, user configuration is kept to a
minimum. Two settings are available: minimum. Two settings are available:
- **Boot order**: Since Infix maintains two copies of its software image, **Boot order**: Since Infix maintains two copies of its software image,
and as some bootloaders support [netbooting][2], the order in which boot and as some bootloaders support [netbooting][2], the order in which boot
sources are considered can be configured. To select the active sources are considered can be configured. To select the active
source, use [RAUC][]: source, use [RAUC][]:
rauc status mark-active <slot> ```
root@example:~# rauc status mark-active <slot>
...
```
Where `<slot>` is one of: Where `<slot>` is one of:
| `<slot>` | Source | | **`<slot>`** | **Source** |
|------------|---------------------------| |--------------|---------------------------|
| `rootfs.0` | Primary partition | | `rootfs.0` | Primary partition |
| `rootfs.1` | Secondary partition | | `rootfs.1` | Secondary partition |
| `net.0` | Netboot (where supported) | | `net.0` | Netboot (where supported) |
- **Debug**: By default, the kernel will only output errors to the **Debug**: By default, the kernel will only output errors to the
console during boot. Optionally, this can be altered such that all console during boot. Optionally, this can be altered such that all
enabled messages are logged. enabled messages are logged.
On systems using _U-Boot_, this can be enabled by running `fw_setenv On systems using _U-Boot_, this can be enabled by running `fw_setenv
DEBUG 1`. To restore the default behavior, run `fw_setenv DEBUG`. DEBUG 1`. To restore the default behavior, run `fw_setenv DEBUG`.
On systems running _GRUB_, this can be enabled by running On systems running _GRUB_, this can be enabled by running:
`grub-editenv /mnt/aux/grub/grubenv set DEBUG=1`. To restore the
default behavior, run `grub-editenv /mnt/aux/grub/grubenv unset
DEBUG`
```
root@example:~# grub-editenv /mnt/aux/grub/grubenv set DEBUG=1
```
To restore the default behavior, run:
```
root@example:~# grub-editenv /mnt/aux/grub/grubenv unset DEBUG
```
### U-Boot ### U-Boot
@@ -109,7 +115,6 @@ Access to U-Boot's shell is disabled to prevent side-loading of
malicious software. To configure the active boot partition, refer to malicious software. To configure the active boot partition, refer to
the [Bootloader Configuration](#configuration) section. the [Bootloader Configuration](#configuration) section.
### GRUB ### GRUB
Used on _x86_64_ based systems. Neither the _integrity_ nor the Used on _x86_64_ based systems. Neither the _integrity_ nor the
@@ -123,7 +128,6 @@ partition can be selected interactively at boot using the arrow keys. It
is also possible to permanently configure the default partition from is also possible to permanently configure the default partition from
Infix using the [Bootloader Configuration](#configuration). Infix using the [Bootloader Configuration](#configuration).
## System Boot ## System Boot
After the system firmware (BIOS or and [boot loader](boot.md) start After the system firmware (BIOS or and [boot loader](boot.md) start
@@ -132,49 +136,50 @@ password in VPD, are detailed later in this section.
![System boot flowchart](img/fail-secure.svg) ![System boot flowchart](img/fail-secure.svg)
1. Before mounting `/cfg` and `/var` partitions, hosting read-writable 1. Before mounting `/cfg` and `/var` partitions, hosting read-writable
data like `startup-config` and container images, the system first data like `startup-config` and container images, the system first
checks if a factory reset has been requested by the user, if so it checks if a factory reset has been requested by the user, if so it
wipes the contents of these partitions wipes the contents of these partitions
2. Linux boots with a device tree which is used for detecting generic 1. Linux boots with a device tree which is used for detecting generic
make and model of the device, e.g., number of interfaces. It may make and model of the device, e.g., number of interfaces. It may
also reference an EEPROM with [Vital Product Data](vpd.md). That is also reference an EEPROM with [Vital Product Data](vpd.md). That is
where the base MAC address and per-device password hash is stored. where the base MAC address and per-device password hash is stored.
(Generic builds use the same MAC address and password) (Generic builds use the same MAC address and password)
3. On every boot the system's `factory-config` and `failure-config` are 1. On every boot the system's `factory-config` and `failure-config` are
generated from the YANG[^2] models of the current firmware version. generated from the YANG[^2] models of the current firmware version.
This ensures that a factory reset device can always boot, and that This ensures that a factory reset device can always boot, and that
there is a working fail safe, or rather *fail secure*, mode there is a working fail safe, or rather *fail secure*, mode
4. On first power-on, and after a factory reset, the system does not 1. On first power-on, and after a factory reset, the system does not
have a `startup-config`, in which case `factory-config` is copied have a `startup-config`, in which case `factory-config` is copied
to `startup-config` -- if a per-product specific version exists it to `startup-config` -- if a per-product specific version exists it
is preferred over the generated one is preferred over the generated one
5. Provided the integrity of the `startup-config` is OK, a system 1. Provided the integrity of the `startup-config` is OK, a system
service loads and activates the configuration service loads and activates the configuration
### Failure Modes ### Failure Modes
So, what happens if any of the steps above fail? So, what happens if any of the steps above fail?
**VPD Fail** #### VPD Fail
The per-device password cannot be read, or is corrupt, so the system The per-device password cannot be read, or is corrupt, so the system
`factory-config` and `failure-config` are not generated: `factory-config` and `failure-config` are not generated:
1. First boot, or after factory reset: `startup-config` cannot be 1. First boot, or after factory reset: `startup-config` cannot be
created or loaded, and `failure-config` cannot be loaded. The created or loaded, and `failure-config` cannot be loaded. The
system ends up in an unrecoverable state, i.e., **RMA[^3] Mode** system ends up in an unrecoverable state, i.e., **RMA[^3] Mode**
2. The system has booted (at least) once with correct VPD and password 1. The system has booted (at least) once with correct VPD and password
and already has a `startup-config`. Provided the `startup-config` and already has a `startup-config`. Provided the `startup-config`
is OK (see below), it is loaded and system boots successfully is OK (see below), it is loaded and system boots successfully
In both cases, external factory reset modes/button will not help, and In both cases, external factory reset modes/button will not help, and
in the second case will cause the device to fail on the next boot. in the second case will cause the device to fail on the next boot.
> [!NOTE]
> The second case does not yet have any warning or event that can be > The second case does not yet have any warning or event that can be
> detected from the outside. This is planned for a later release. > detected from the outside. This is planned for a later release.
**Broken startup-config** #### Broken startup-config
If loading `startup-config` fails for some reason, e.g., invalid JSON If loading `startup-config` fails for some reason, e.g., invalid JSON
syntax, failed validation against the system's YANG model, or a bug in syntax, failed validation against the system's YANG model, or a bug in
@@ -194,9 +199,7 @@ link-local, and device discovery protocols: LLDP, mDNS-SD. The login
and shell prompt are set to `failure-c0-ff-ee`, the last three octets of and shell prompt are set to `failure-c0-ff-ee`, the last three octets of
the device's base MAC address. the device's base MAC address.
## System Upgrade
System Upgrade
--------------
Much of the minutiae of software upgrades is delegated to [RAUC][], Much of the minutiae of software upgrades is delegated to [RAUC][],
which offers lots of benefits out-of-the-box: which offers lots of benefits out-of-the-box:
@@ -204,18 +207,19 @@ which offers lots of benefits out-of-the-box:
- Upgrade Bundles are always signed, such that their authenticity can - Upgrade Bundles are always signed, such that their authenticity can
be verified by the running operating system, before the new one is be verified by the running operating system, before the new one is
installed. installed.
- The bureaucracy of interfacing with different bootloaders, manage - The bureaucracy of interfacing with different bootloaders, manage
the boot order, is a simple matter of providing a compatible the boot order, is a simple matter of providing a compatible
configuration. configuration.
- Updates can be sourced from the local filesystem (including external - Updates can be sourced from the local filesystem (including external
media like USB sticks or SD-cards) and from remote servers using FTP media like USB sticks or SD-cards) and from remote servers using FTP
or HTTP(S). or HTTP(S).
To initiate a system upgrade from the shell[^1], run: To initiate a system upgrade from the shell[^1], run:
rauc install <file|url> ```
root@example:~# rauc install <file|url>
...
```
Where the file or URL points to a [RAUC Upgrade Bundle](#rauc-upgrade-bundle). Where the file or URL points to a [RAUC Upgrade Bundle](#rauc-upgrade-bundle).
@@ -225,9 +229,7 @@ will then boot from the newly installed image. Since the partition
from which you were originally running is now inactive, running the from which you were originally running is now inactive, running the
same upgrade command again will bring both partitions into sync. same upgrade command again will bring both partitions into sync.
## Image Formats
Image Formats
-------------
### SquashFS Image ### SquashFS Image
@@ -279,7 +281,6 @@ validate the SquashFS's contents. This path was chosen because:
In its full form, it can be used to netboot Infix, as it contains all In its full form, it can be used to netboot Infix, as it contains all
the information needed by U-Boot in a single file. the information needed by U-Boot in a single file.
### RAUC Upgrade Bundle ### RAUC Upgrade Bundle
**Canonical Name**: `infix-${ARCH}.pkg` **Canonical Name**: `infix-${ARCH}.pkg`
@@ -293,7 +294,6 @@ system.
When performing a [System Upgrade](#system-upgrade), this is the format When performing a [System Upgrade](#system-upgrade), this is the format
to use. to use.
### Disk Image ### Disk Image
**Canonical Name**: `disk.img` **Canonical Name**: `disk.img`
@@ -302,35 +302,37 @@ Infix runs from a block device (e.g. eMMC or virtio disk) with the
following layout. The disk is expected to use the GPT partitioning following layout. The disk is expected to use the GPT partitioning
scheme. Partitions marked with an asterisk are optional. scheme. Partitions marked with an asterisk are optional.
.-----------. ```
| GPT Table | .-----------.
:-----------: | GPT Table |
| boot* | :-----------:
:-----------: | boot* |
| aux | :-----------:
:-----------: | aux |
| | :-----------:
| primary | | |
| | | primary |
:-----------: | |
| | :-----------:
| secondary | | |
| | | secondary |
:-----------: | |
| cfg | :-----------:
:-----------: | cfg |
| | :-----------:
| var* | | |
| | | var* |
'-----------' | |
'-----------'
```
#### `boot` - Bootloader #### `boot` - Bootloader
| Parameter | Value | | **Parameter** | **Value** |
|-----------|-----------------------------------------| |---------------|-----------------------------------------|
| Required | No | | Required | No |
| Size | 4 MiB | | Size | 4 MiB |
| Format | Raw binary, as dictated by the hardware | | Format | Raw binary, as dictated by the hardware |
Optional partition containing the system's bootloader. May also reside Optional partition containing the system's bootloader. May also reside
in a separate storage device, e.g. a serial FLASH. in a separate storage device, e.g. a serial FLASH.
@@ -340,11 +342,11 @@ the GRUB bootloader.
#### `aux` - Auxiliary Data #### `aux` - Auxiliary Data
| Parameter | Value | | **Parameter** | **Value** |
|-----------|-----------------| |---------------|-----------------|
| Required | Yes | | Required | Yes |
| Size | 4 MiB | | Size | 4 MiB |
| Format | EXT4 filesystem | | Format | EXT4 filesystem |
Holds information that is shared between Infix and its bootloader, Holds information that is shared between Infix and its bootloader,
such as image signatures required to validate the chain of trust, such as image signatures required to validate the chain of trust,
@@ -353,10 +355,10 @@ bootloader configuration etc.
Typical layout when using U-Boot bootloader: Typical layout when using U-Boot bootloader:
``` ```
/ /
├ primary.itbh ├ primary.itbh
├ secondary.itbh ├ secondary.itbh
└ uboot.env └ uboot.env
``` ```
During boot, an ITB header along with the corresponding root During boot, an ITB header along with the corresponding root
@@ -370,11 +372,11 @@ required to configure the boot order.
#### `primary`/`secondary` - Root Filesystems #### `primary`/`secondary` - Root Filesystems
| Parameter | Value | | **Parameter** | **Value** |
|-----------|-------------------| |---------------|-------------------|
| Required | Yes | | Required | Yes |
| Size | >= 256 MiB | | Size | >= 256 MiB |
| Format | Squash filesystem | | Format | Squash filesystem |
Holds the [SquashFS Image](#squashfs-image). Two copies exist so that Holds the [SquashFS Image](#squashfs-image). Two copies exist so that
an incomplete upgrade does not brick the system, and to allow fast an incomplete upgrade does not brick the system, and to allow fast
@@ -382,22 +384,22 @@ rollbacks when upgrading to a new version.
#### `cfg` - Configuration Data #### `cfg` - Configuration Data
| Parameter | Value | | **Parameter** | **Value** |
|-----------|-----------------| |---------------|-----------------|
| Required | Yes | | Required | Yes |
| Size | >= 16 MiB | | Size | >= 16 MiB |
| Format | EXT4 filesystem | | Format | EXT4 filesystem |
Non-volatile storage of the system configuration and user data. Non-volatile storage of the system configuration and user data.
Concretely, user data is everything stored under `/root` and `/home`. Concretely, user data is everything stored under `/root` and `/home`.
#### `var` - Variable Data #### `var` - Variable Data
| Parameter | Value | | **Parameter** | **Value** |
|-----------|-----------------| |---------------|-----------------|
| Required | No | | Required | No |
| Size | >= 16 MiB | | Size | >= 16 MiB |
| Format | EXT4 filesystem | | Format | EXT4 filesystem |
Persistent storage for everything under `/var`. This is maintained as Persistent storage for everything under `/var`. This is maintained as
a separate filesystem from the data in `cfg`, because while the system a separate filesystem from the data in `cfg`, because while the system
@@ -410,7 +412,7 @@ If `var` is not available, Infix will still persist `/var/lib` using
[^1]: See [Upgrade & Boot Order](upgrade.md) for more information. [^1]: See [Upgrade & Boot Order](upgrade.md) for more information.
[^2]: YANG is a modeling language from IETF, replacing that used for [^2]: YANG is a modeling language from IETF, replacing that used for
SNMP (MIB), used to describe the subsystems and properties of SNMP (MIB), used to describe the subsystems and properties of
the system. the system.
[^3]: Return Merchandise Authorization (RMA), i.e., broken beyond repair [^3]: Return Merchandise Authorization (RMA), i.e., broken beyond repair
by end-user and eligible for return to manufacturer. by end-user and eligible for return to manufacturer.
[^4]: Customer specific builds can define their own `failure-config`. [^4]: Customer specific builds can define their own `failure-config`.
@@ -420,7 +422,6 @@ If `var` is not available, Infix will still persist `/var/lib` using
security problems on the network. E.g., start forwarding traffic security problems on the network. E.g., start forwarding traffic
between previously isolated VLANs. between previously isolated VLANs.
[2]: netboot.md [2]: netboot.md
[FIT]: https://u-boot.readthedocs.io/en/latest/usage/fit.html [FIT]: https://u-boot.readthedocs.io/en/latest/usage/fit.html
[RAUC]: https://rauc.io [RAUC]: https://rauc.io
+88 -92
View File
@@ -1,11 +1,9 @@
Branding & Releases # Branding & Releases
===================
This document is for projects using Infix as a br2-external, i.e., OEMs. This document is for projects using Infix as a br2-external, i.e., OEMs
that want to create *their own "Spin"* of Infix.
## Branding
Branding
--------
Branding is done in menuconfig, there are several settings affecting Branding is done in menuconfig, there are several settings affecting
it, most are in the Infix external subsection called "Branding", but it, most are in the Infix external subsection called "Branding", but
@@ -24,25 +22,18 @@ check this for you and you may end up with odd results.
Verify the result after a build by inspecting: Verify the result after a build by inspecting:
- `output/images/*`: names, missing prefix, etc. - `output/images/*`: names, missing prefix, etc.
- `output/target/etc/os-release`: this file is sourced by - `output/target/etc/os-release`: this file is sourced by other build
other build scripts, e.g., `mkgns3a.sh`. For reference, see scripts, e.g., `mkgns3a.sh`. For reference, see [os-release(5)][]
https://www.freedesktop.org/software/systemd/man/os-release.html
> **Note:** to get proper GIT revision (hash) from your composed OS, > [!IMPORTANT]
> remember in menuconfig to set `INFIX_OEM_PATH`. When unset the > To get a proper GIT revision (hash) from your OS spin, remember to set
> Infix `post-build.sh` script defaults to the Infix base path. The > in menuconfig `INFIX_OEM_PATH`. When unset, the Infix `post-build.sh`
> revision is stored in the file `/etc/os-release` as BUILD_ID and > script defaults to the Infix base path. The revision is stored in the
> is also in the file `/etc/version`. See below for more info. > file `/etc/os-release` as `BUILD_ID`, also in the file `/etc/version`.
> See below for more info.
[^1]: The base MAC address is defined in the device's Vital Product ## Factory & Failure Config
Data (VPD) EEPROM, or similar, which is used by the kernel to
create the system interfaces. This MAC address is usually also
printed on a label on the device.
Factory & Failure Config
------------------------
To support booting the same image (CPU architecture) on multiple boards, To support booting the same image (CPU architecture) on multiple boards,
Infix by default generates the device's initial configuration every time Infix by default generates the device's initial configuration every time
@@ -56,7 +47,6 @@ However, for custom builds of Infix it is possible to override this with
a single static `/etc/factory-config.cfg` (and failure-config) in your a single static `/etc/factory-config.cfg` (and failure-config) in your
rootfs overlay -- with a [VPD](vpd.md) you can even support several! rootfs overlay -- with a [VPD](vpd.md) you can even support several!
### Variables & Format Specifiers ### Variables & Format Specifiers
Parts of the configuration you likely always want to generated, like the Parts of the configuration you likely always want to generated, like the
@@ -65,22 +55,22 @@ unique (per-device with a VPD) password hash. This section lists the
available keywords, see the next section for examples of how to use available keywords, see the next section for examples of how to use
them: them:
- **Default password hash:** `$factory$` (from VPD, .dtb, or built-in) - **Default password hash:** `$factory$` (from VPD, .dtb, or built-in)
XPath: `/ietf-system:system/authentication/user/password` XPath: `/ietf-system:system/authentication/user/password`
- **Default SSH and NETCONF hostkey:** `genkey` (regenerated at factory reset) - **Default SSH and NETCONF hostkey:** `genkey` (regenerated at factory reset)
XPath: `/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='genkey']` XPath: `/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='genkey']`
- **Hostname format specifiers:** - **Hostname format specifiers:**
XPath: `/ietf-system:system/hostname` XPath: `/ietf-system:system/hostname`
- `%i`: OS ID, from `/etc/os-release`, from Menuconfig branding - `%i`: OS ID, from `/etc/os-release`, from Menuconfig branding
- `%h`: Default hostname, from `/etc/os-release`, from branding - `%h`: Default hostname, from `/etc/os-release`, from branding
- `%m`: NIC specific part of base MAC, e.g., to `c0-ff-ee` - `%m`: NIC specific part of base MAC, e.g., to `c0-ff-ee`
- `%%`: Literal % - `%%`: Literal %
### Static Files ### Static Files
> **Caveat:** maintaining static a factory-config and failure-config may > [!CAUTION]
> seem like an obvious choice, but as YANG models evolve (even the IETF > Maintaining a static `factory-config` and `failure-config` may seem
> like an obvious choice, but as YANG models evolve (even the IETF
> models get upgraded), you may need to upgrade your static files. > models get upgraded), you may need to upgrade your static files.
First, for one-off builds (one image per product), the simplest way is First, for one-off builds (one image per product), the simplest way is
@@ -103,9 +93,8 @@ after `00-probe` has run. The lower case version of the string is used.
I.e., create a rootfs overlay that provides any combination of: I.e., create a rootfs overlay that provides any combination of:
- `/usr/share/product/<PRODUCT>/etc/factory-config.cfg` - `/usr/share/product/<PRODUCT>/etc/factory-config.cfg`
- `/usr/share/product/<PRODUCT>/etc/failure-config.cfg` - `/usr/share/product/<PRODUCT>/etc/failure-config.cfg`
### Dynamically Generated ### Dynamically Generated
@@ -113,14 +102,14 @@ The generated `factory-config` and `failure-config` files consist of
both static JSON files and part generated files at runtime for each both static JSON files and part generated files at runtime for each
device. The resulting files are written to the RAM disk in `/run`: device. The resulting files are written to the RAM disk in `/run`:
- `/run/confd/factory-config.gen` - `/run/confd/factory-config.gen`
- `/run/confd/failure-config.gen` - `/run/confd/failure-config.gen`
Provided no custom overrides (see above) have been installed already, Provided no custom overrides (see above) have been installed already,
these files are then copied to: these files are then copied to:
- `/etc/factory-config.cfg` - `/etc/factory-config.cfg`
- `/etc/failure-config.cfg` - `/etc/failure-config.cfg`
... where the bootstrap process expects them to be in the next step. ... where the bootstrap process expects them to be in the next step.
@@ -132,29 +121,33 @@ base hostname, set `BR2_TARGET_GENERIC_HOSTNAME` in your defconfig.
The static files are installed by Infix `confd` in `/usr/share/confd/` The static files are installed by Infix `confd` in `/usr/share/confd/`
at build time. It contains two subdirectories: at build time. It contains two subdirectories:
/usr/share/confd/ ```
|- factory.d/ /usr/share/confd/
| |- 10-foo.json |- factory.d/
| |- 10-bar.json | |- 10-foo.json
| `- 10-qux.json | |- 10-bar.json
`- failure.d/ | `- 10-qux.json
|- 10-xyzzy.json `- failure.d/
`- 10-garply.json |- 10-xyzzy.json
`- 10-garply.json
```
To override, or extend, these files in you br2-external, set up a rootfs To override, or extend, these files in you br2-external, set up a rootfs
overlay and add it last in `BR2_ROOTFS_OVERLAY`. Your overlay can look overlay and add it last in `BR2_ROOTFS_OVERLAY`. Your overlay can look
something like this: something like this:
./board/common/rootfs/ ```
|- etc/ ./board/common/rootfs/
| |- confdrc # See below |- etc/
| `- confdrc.local | |- confdrc # See below
`- usr/ | `- confdrc.local
`- share/ `- usr/
`- confd/ `- share/
|- 10-foo.json # Override Infix foo `- confd/
|- 30-bar.json # Extend, probably 10-bar.json |- 10-foo.json # Override Infix foo
`- 30-fred.json # Extend, your own defaults |- 30-bar.json # Extend, probably 10-bar.json
`- 30-fred.json # Extend, your own defaults
```
Using the same filename in your overlay, here `10-foo.json`, completely Using the same filename in your overlay, here `10-foo.json`, completely
replaces the contents of the same file provided by Infix. If you just replaces the contents of the same file provided by Infix. If you just
@@ -168,17 +161,17 @@ provide a few custom ones that the `bootstrap` knows about, e.g.,
`gen-ifs-custom` that overrides `20-interfaces.json`. See the `gen-ifs-custom` that overrides `20-interfaces.json`. See the
bootstrap script for more help, and up-to-date information. bootstrap script for more help, and up-to-date information.
> **Note:** you may not need to provide your own `/etc/confdrc`. The > [!TIP]
> one installed by `confd` is usually enough. However, if you want to > You may not need to provide your own `/etc/confdrc` for your spin.
> adjust the behavior of `bootstrap` you may want to override it. There > The one installed by `confd` is usually enough. However, if you want
> is also `confdrc.local`, which usually is enough to change arguments > to adjust the behavior of `bootstrap` you may want to override it.
> to scripts like `gen-interfaces`, e.g., to create a bridge by default, > There is also `confdrc.local`, which usually is enough to change
> you may want to look into `GEN_IFACE_OPTS`. > arguments to scripts like `gen-interfaces`, e.g., to create a bridge
> by default, you may want to look into `GEN_IFACE_OPTS`.
### Example Snippets ### Example Snippets
**IETF System:** #### IETF System
```hsib ```hsib
"ietf-system:system": { "ietf-system:system": {
@@ -211,15 +204,16 @@ bootstrap script for more help, and up-to-date information.
The `motd-banner` is a binary type, which is basically a Base64 encoded The `motd-banner` is a binary type, which is basically a Base64 encoded
text file without line breaks (`-w0`): text file without line breaks (`-w0`):
```bash ```
$ echo "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCAtLSBhIE5ldHdvcmsgT3BlcmF0aW5nIFN5c3RlbQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQuZ2l0aHViLmlvCictJy0tLSctJwo=" |base64 -d $ echo "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCAtLSBhIE5ldHdvcmsgT3BlcmF0aW5nIFN5c3RlbQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQuZ2l0aHViLmlvCictJy0tLSctJwo=" \
| base64 -d
.-------. .-------.
| . . | Infix OS — Immutable.Friendly.Secure | . . | Infix OS — Immutable.Friendly.Secure
|-. v .-| https://kernelkit.github.io |-. v .-| https://kernelkit.github.io
'-'---'-' '-'---'-'
``` ```
**IETF Keystore** #### IETF Keystore
Notice how both the public and private keys are left empty here, this Notice how both the public and private keys are left empty here, this
cause them to be always automatically regenerated after each factory reset. cause them to be always automatically regenerated after each factory reset.
@@ -245,7 +239,7 @@ use-case and not documented here.
}, },
``` ```
**IETF NETCONF Server** #### IETF NETCONF Server
```json ```json
"ietf-netconf-server:netconf-server": { "ietf-netconf-server:netconf-server": {
@@ -278,7 +272,8 @@ use-case and not documented here.
}, },
``` ```
**Infix Services** #### Infix Services
```json ```json
"infix-services:ssh": { "infix-services:ssh": {
"enabled": true, "enabled": true,
@@ -300,10 +295,7 @@ use-case and not documented here.
} }
``` ```
## Integration
Integration
-----------
When integrating your software stack with Infix there may be protocols When integrating your software stack with Infix there may be protocols
that want to change system settings like hostname and dynamically set that want to change system settings like hostname and dynamically set
@@ -330,7 +322,7 @@ root@infix-00-00-00:~# cat hostnm.xml
</system> </system>
root@infix-00-00-00:~# edit hostnm.xml root@infix-00-00-00:~# edit hostnm.xml
root@infix-00-00-00:~# sysrepocfg -Ehostnm.xml root@infix-00-00-00:~# sysrepocfg -Ehostnm.xml
root@example:~# root@example:~#
``` ```
Second, perform all changes on `running-config`, the running datastore. Second, perform all changes on `running-config`, the running datastore.
@@ -344,8 +336,8 @@ activate all.)
You can consider the system composed of two entities: You can consider the system composed of two entities:
- NETCONF starts up the system using `startup-config`, then - NETCONF starts up the system using `startup-config`, then
- Hands over control to your application at runtime - Hands over control to your application at runtime
Infix is prepared for this by already having two "runlevels" for these Infix is prepared for this by already having two "runlevels" for these
two states. The `startup-config` is applied in runlevel S (bootstrap) two states. The `startup-config` is applied in runlevel S (bootstrap)
@@ -353,15 +345,13 @@ and the system then enters runlevel 2 for normal operation.
This allow you to keep a set of functionality that is provided by the This allow you to keep a set of functionality that is provided by the
underlying system, and another managed by your application. You can underlying system, and another managed by your application. You can
of course in your br2-external provide a sysrepo plugin that block of course in your br2-external provide a sysrepo plugin that block
operations on certain datastores when your application is enabled. operations on certain datastores when your application is enabled.
E.g., to prevent changes to startup after initial deployment. In E.g., to prevent changes to startup after initial deployment. In
that case a proper factory reset would be needed to get back to a that case a proper factory reset would be needed to get back to a
"pre-deployment" state where you can reconfigure your baseline. "pre-deployment" state where you can reconfigure your baseline.
## Releases
Releases
--------
A release build requires the global variable `INFIX_RELEASE` to be set. A release build requires the global variable `INFIX_RELEASE` to be set.
It can be derived from GIT, if the source tree is kept in GIT VCS. First, It can be derived from GIT, if the source tree is kept in GIT VCS. First,
@@ -371,14 +361,14 @@ let us talk about versioning in general.
Two popular scheme for versioning a product derived from Infix: Two popular scheme for versioning a product derived from Infix:
1. Track Infix major.minor, e.g. *Foobar v23.08.z*, where `z` is 1. Track Infix major.minor, e.g. *Foobar v23.08.z*, where `z` is
your patch level. I.e., Foobar v23.08.0 could be based on Infix your patch level. I.e., Foobar v23.08.0 could be based on Infix
v23.08.0, or v23.08.12, it is up to you. Maybe you based it on v23.08.0, or v23.08.12, it is up to you. Maybe you based it on
v23.08.12 and then back ported changes from v23.10.0, but it was v23.08.12 and then back ported changes from v23.10.0, but it was
the first release you made to your customer(s). the first release you made to your customer(s).
2. Start from v1.0.0 and step the major number every time you sync 1. Start from v1.0.0 and step the major number every time you sync
with a new Infix release, or every time Infix bumps to the next with a new Infix release, or every time Infix bumps to the next
Buildroot LTS. Buildroot LTS.
The important thing is to be consistent, not only for your own sake, The important thing is to be consistent, not only for your own sake,
but also for your end customers. The *major.minor.patch* style is but also for your end customers. The *major.minor.patch* style is
@@ -386,10 +376,10 @@ the most common and often recommended style, which usually maps well
to other systems, e.g. PROFINET GSDML files require this (*VX.Y.Z*). to other systems, e.g. PROFINET GSDML files require this (*VX.Y.Z*).
But you can of course use only two numbers, *major.minor*, as well. But you can of course use only two numbers, *major.minor*, as well.
> [!WARNING]
> What could be confusing, however, is if you use the name *Infix* > What could be confusing, however, is if you use the name *Infix*
> with your own versioning scheme. > with your own versioning scheme.
### Specifying Versioning Information ### Specifying Versioning Information
Two optional environment variables control the version information Two optional environment variables control the version information
@@ -416,4 +406,10 @@ generated file names like disk images, etc.
**Default:** `${INFIX_BUILD_ID}` **Default:** `${INFIX_BUILD_ID}`
[NanoPi R2S]: https://github.com/kernelkit/infix/blob/main/board/aarch64/r2s/rootfs/etc/factory-config.cfg [^1]: The base MAC address is defined in the device's Vital Product
Data (VPD) EEPROM, or similar, which is used by the kernel to
create the system interfaces. This MAC address is usually also
printed on a label on the device.
[NanoPi R2S]: https://github.com/kernelkit/infix/blob/main/board/aarch64/r2s/rootfs/etc/factory-config.cfg
[os-release(5)]: https://www.freedesktop.org/software/systemd/man/os-release.html
+4 -4
View File
@@ -51,9 +51,10 @@ Linux to use.
### Configure USB port ### Configure USB port
> **Note:** You can only configure USB ports known to the system. See > [!NOTE]
> `show hardware` in admin-exec context. (Use `do` prefix in configure > You can only configure USB ports known to the system. See the CLI
> context.) > command `show hardware` in admin-exec context. (Use `do` prefix in
> configure context.)
``` ```
admin@example:/> configure admin@example:/> configure
@@ -84,5 +85,4 @@ cached data to disk before returning the prompt:
admin@example:~$ sudo umount /media/log admin@example:~$ sudo umount /media/log
``` ```
[1]: https://www.rfc-editor.org/rfc/rfc8348.html [1]: https://www.rfc-editor.org/rfc/rfc8348.html
+38 -35
View File
@@ -8,10 +8,10 @@ details how to log to external media or remote syslog servers.
It is also possible to set up the device to act as a syslog server (log It is also possible to set up the device to act as a syslog server (log
sink), this is covered briefly at the very end of this document. sink), this is covered briefly at the very end of this document.
> **Note:** the native logging cannot be modified, only the log file > [!NOTE]
> rotation can be changed. Please see the `dir` admin-exec command for > The default logging setup in the system cannot be modified, only the
> a listing of existing native log files. > log file rotation. Please see the `dir` admin-exec command for a
> listing of existing log files.
## Log to File ## Log to File
@@ -21,7 +21,7 @@ an example.
For a list of available log facilities, see the table in a later section. For a list of available log facilities, see the table in a later section.
```bash ```
admin@example:/> configure admin@example:/> configure
admin@example:/config/> edit syslog admin@example:/config/> edit syslog
admin@example:/config/syslog/> edit actions log-file file:/media/log/mylog admin@example:/config/syslog/> edit actions log-file file:/media/log/mylog
@@ -37,11 +37,11 @@ admin@example:/config/syslog/actions/log-file/file:/media/log/mylog/> leave
admin@example:/> admin@example:/>
``` ```
> **Note:** the `log-file` syntax requires the leading prefix `file:`. > [!IMPORTANT]
> If the path is not absolute, e.g., `file:mylog`, the file is saved to > The `log-file` syntax requires the leading prefix `file:`. If the
> the system default path, i.e., `/log/mylog`. In this case, verify > path is not absolute, e.g., `file:mylog`, the file is saved to the
> that the filename is not already in use. > system default path, i.e., `/log/mylog`. In this case, verify that
> the filename is not already in use.
## Log Rotation ## Log Rotation
@@ -51,13 +51,16 @@ disk with outdated logs. A rotated file is saved in stages and older
ones are also compressed (using `gzip`). Use the `show log` command in ones are also compressed (using `gzip`). Use the `show log` command in
admin-exec context to start the log file viewer: admin-exec context to start the log file viewer:
admin@example:/config/syslog/> do show log ```
log log.0 log.1.gz log.2.gz log.3.gz log.4.gz log.5.gz admin@example:/config/syslog/> do show log
admin@example:/config/syslog/> do show log log.1.gz log log.0 log.1.gz log.2.gz log.3.gz log.4.gz log.5.gz
admin@example:/config/syslog/> do show log log.1.gz
```
> **Tip:** use the Tab key on your keyboard list available log files. > [!TIP]
> The `do` prefix is also very useful in configure context to access > Use the Tab key on your keyboard list available log files. The `do`
> commands from admin-exec context. > prefix is also very useful in configure context to access commands
> from admin-exec context.
By default 10 compressed older files are saved. Here the oldest is By default 10 compressed older files are saved. Here the oldest is
`log.5.gz` and the most recently rotated one is `log.0`. `log.5.gz` and the most recently rotated one is `log.0`.
@@ -66,8 +69,8 @@ Log file rotation can be configured both globally and per log file.
Here we show the global settings, the set up is the same for per log Here we show the global settings, the set up is the same for per log
file, which if unset inherit the global settings: file, which if unset inherit the global settings:
```bash ```
admin@example:/> configure admin@example:/> configure
admin@example:/config/> edit syslog file-rotation admin@example:/config/> edit syslog file-rotation
admin@example:/config/syslog/file-rotation/> show admin@example:/config/syslog/file-rotation/> show
admin@example:/config/syslog/file-rotation/> admin@example:/config/syslog/file-rotation/>
@@ -76,7 +79,7 @@ admin@example:/config/syslog/file-rotation/>
The defaults are not shown. We can inspect them by asking the YANG The defaults are not shown. We can inspect them by asking the YANG
model for the help texts: model for the help texts:
```bash ```
admin@example:/config/syslog/file-rotation/> help admin@example:/config/syslog/file-rotation/> help
max-file-size number-of-files max-file-size number-of-files
admin@example:/config/syslog/file-rotation/> help max-file-size admin@example:/config/syslog/file-rotation/> help max-file-size
@@ -102,17 +105,16 @@ DEFAULT
To change the defaults to something smaller, 512 kiB and 20 (remember To change the defaults to something smaller, 512 kiB and 20 (remember
everything after .0 is compressed, and text compresses well): everything after .0 is compressed, and text compresses well):
```bash ```
admin@example:/config/syslog/file-rotation/> set max-file-size 512 admin@example:/config/syslog/file-rotation/> set max-file-size 512
admin@example:/config/syslog/file-rotation/> set number-of-files 20 admin@example:/config/syslog/file-rotation/> set number-of-files 20
admin@example:/config/syslog/file-rotation/> show admin@example:/config/syslog/file-rotation/> show
number-of-files 20; number-of-files 20;
max-file-size 512; max-file-size 512;
admin@example:/config/syslog/file-rotation/> leave admin@example:/config/syslog/file-rotation/> leave
admin@example:/> admin@example:/>
``` ```
## Log Format ## Log Format
There are three major syslog log formats, the default is [RFC3164][] for There are three major syslog log formats, the default is [RFC3164][] for
@@ -121,9 +123,11 @@ and remote log server capabilities, or policies, the [RFC5424][] format
is often preferred since it not only has better time resolution but also is often preferred since it not only has better time resolution but also
supports structured logging: supports structured logging:
BSD : myproc[8710]: Kilroy was here. ```
RFC3164 : Aug 24 05:14:15 192.0.2.1 myproc[8710]: Kilroy was here. BSD : myproc[8710]: Kilroy was here.
RFC5424 : 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - Kilroy was here. RFC3164 : Aug 24 05:14:15 192.0.2.1 myproc[8710]: Kilroy was here.
RFC5424 : 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - Kilroy was here.
```
The BSD format is only applicable to remote logging. It remains the The BSD format is only applicable to remote logging. It remains the
default for compatibility reasons, and is recommended since the device default for compatibility reasons, and is recommended since the device
@@ -132,7 +136,7 @@ perform time stamping at the time of arrival.
Configuring the log format is the same for log files and remotes: Configuring the log format is the same for log files and remotes:
```bash ```
admin@example:/config/> edit syslog actions log-file file:foobar admin@example:/config/> edit syslog actions log-file file:foobar
admin@example:/config/syslog/actions/log-file/file:foobar/> set log-format admin@example:/config/syslog/actions/log-file/file:foobar/> set log-format
bsd rfc3164 rfc5424 bsd rfc3164 rfc5424
@@ -141,9 +145,6 @@ admin@example:/config/syslog/actions/log-file/file:foobar/> leave
admin@example:/> admin@example:/>
``` ```
[RFC3164]: https://datatracker.ietf.org/doc/html/rfc3164
[RFC5424]: https://datatracker.ietf.org/doc/html/rfc5424
## Log to Remote Server ## Log to Remote Server
Logging to a remote syslog server is the recommended way of supervising Logging to a remote syslog server is the recommended way of supervising
@@ -158,7 +159,7 @@ remote syslog servers do not support receiving time stamped log messages
-- this is of course entirely dependent on how the remote server is set -- this is of course entirely dependent on how the remote server is set
up, as well as local policy. up, as well as local policy.
```bash ```
admin@example:/config/> edit syslog admin@example:/config/> edit syslog
actions file-rotation server actions file-rotation server
admin@example:/config/> edit syslog actions destination moon admin@example:/config/> edit syslog actions destination moon
@@ -172,16 +173,16 @@ admin@example:/config/syslog/actions/destination/moon/> leave
admin@example:/> admin@example:/>
``` ```
> **Note:** the alternatives shown below each prompt in the example > [!TIP]
> above can be found by tapping the Tab key. > The alternatives shown below each prompt in the example above can be
> found by tapping the Tab key.
## Acting as a Log Server ## Acting as a Log Server
The syslog server can act as a log sink for other devices on a LAN. For The syslog server can act as a log sink for other devices on a LAN. For
this to work you need a static IP address, here we use 10.0.0.1/24. this to work you need a static IP address, here we use 10.0.0.1/24.
```bash ```
admin@example:/> configure admin@example:/> configure
admin@example:/config/> edit syslog server admin@example:/config/> edit syslog server
admin@example:/config/syslog/server/> set enabled true admin@example:/config/syslog/server/> set enabled true
@@ -194,7 +195,6 @@ See the above [Log to File](#log-to-file) section on how to set up
filtering of received logs to local files. Please note, filtering based filtering of received logs to local files. Please note, filtering based
on property, e.g., hostname, is not supported yet. on property, e.g., hostname, is not supported yet.
### Facilities ### Facilities
| **Code** | **Facility** | **Description** | | **Code** | **Facility** | **Description** |
@@ -225,3 +225,6 @@ on property, e.g., hostname, is not supported yet.
| 23 | web* | local7, reserved for nginx web server | | 23 | web* | local7, reserved for nginx web server |
Facilities marked `*` are local augments to the model. Facilities marked `*` are local augments to the model.
[RFC3164]: https://datatracker.ietf.org/doc/html/rfc3164
[RFC5424]: https://datatracker.ietf.org/doc/html/rfc5424
+173 -126
View File
@@ -1,19 +1,16 @@
Regression Testing with Infamy # Regression Testing with Infamy
==============================
Infix comes with a test suite that is intended to provide end-to-end Infix comes with a test suite that is intended to provide end-to-end
verification of supported features. Generally speaking, this means verification of supported features. Generally speaking, this means that
that one or more DUTs are configured over NETCONF; the resulting one or more DUTs are configured over NETCONF or RESTCONF; the resulting
network is then black-box tested by injecting and inspecting network network is then black-box tested by injecting and inspecting network
traffic at various points. traffic at various points.
This document is intended to be a practical guide on how to run, This document is intended to be a practical guide on how to run, develop
develop and debug tests. There is a separate document describing the and debug tests. There is a separate document describing the [Test
[Test System Architecture](test-arch.md). System Architecture](test-arch.md).
## Modes of Testing
Modes of Testing
----------------
### Virtual Devices ### Virtual Devices
@@ -21,23 +18,33 @@ By default, tests are run on a topology made up of virtual Infix nodes
using [Qeneth][]. To run the full regression test suite: build Infix using [Qeneth][]. To run the full regression test suite: build Infix
for `x86_64`: for `x86_64`:
$ make x86_64_defconfig ```
$ make $ make x86_64_defconfig
$ make test ...
$ make
...
$ make test
...
```
### Physical Devices ### Physical Devices
To run the tests on a preexisting topology from the host's network To run the tests on a preexisting topology from the host's network
namespace, specify the `host` `TEST_MODE`: namespace, specify the `host` `TEST_MODE`:
$ make TEST_MODE=host test ```
$ make TEST_MODE=host test
...
```
This typically used when testing on physical hardware. By default the This typically used when testing on physical hardware. By default the
topology will be sourced from `/etc/infamy.dot`, but this can be topology will be sourced from `/etc/infamy.dot`, but this can be
overwritten by setting the `TOPOLOGY` variable: overwritten by setting the `TOPOLOGY` variable:
$ make TEST_MODE=host TOPOLOGY=~/my-topology.dot test ```
$ make TEST_MODE=host TOPOLOGY=~/my-topology.dot test
...
```
### `make run` Devices ### `make run` Devices
@@ -48,26 +55,29 @@ instance is configured to use TAP networking.
When the instance is running, you can open a separate terminal and run When the instance is running, you can open a separate terminal and run
the subset of the test suite that can be mapped to it: the subset of the test suite that can be mapped to it:
$ make TEST_MODE=run test ```
$ make TEST_MODE=run test
...
```
## Interactive Usage
Interactive Usage
-----------------
When developing and debugging tests, the overhead of repeatedly When developing and debugging tests, the overhead of repeatedly
setting up and tearing down the test environment can quickly start to setting up and tearing down the test environment can quickly start to
weigh you down. In these situation, you can start an interactive test weigh you down. In these situation, you can start an interactive test
environment: environment:
$ make test-sh ```
Info: Generating topology $ make test-sh
Info: Generating node YAML Info: Generating topology
Info: Generating executables Info: Generating node YAML
Info: Launching dut1 Info: Generating executables
Info: Launching dut2 Info: Launching dut1
Info: Launching dut3 Info: Launching dut2
Info: Launching dut4 Info: Launching dut3
11:42:52 infamy0:test # Info: Launching dut4
11:42:52 infamy0:test #
```
The example above uses the default mode (`qeneth`), but the `host` and The example above uses the default mode (`qeneth`), but the `host` and
`run` modes also support the `test-sh` target. `run` modes also support the `test-sh` target.
@@ -77,22 +87,27 @@ inside the container running Infamy. It's a very limited environment,
but it has enough to easily run single tests, connect to the virtual but it has enough to easily run single tests, connect to the virtual
devices, and *step* your code. devices, and *step* your code.
### Running Subsets of Tests ### Running Subsets of Tests
Each test case is a separate executable, which can be run without Each test case is a separate executable, which can be run without
arguments: arguments:
11:42:53 infamy0:test # ./case/infix_dhcp/dhcp_basic.py ```
11:42:53 infamy0:test # ./case/infix_dhcp/dhcp_basic.py
```
To run a suite of tests, e.g., only the DHCP client tests, pass the To run a suite of tests, e.g., only the DHCP client tests, pass the
suite as an argument to [9PM][]: suite as an argument to [9PM][]:
11:42:53 infamy0:test # ./9pm/9pm.py case/infix_dhcp/infix_dhcp.yaml ```
11:42:53 infamy0:test # ./9pm/9pm.py case/infix_dhcp/infix_dhcp.yaml
```
To run the suite of all tests: To run the suite of all tests:
11:42:53 infamy0:test # ./9pm/9pm.py case/all.yaml ```
11:42:53 infamy0:test # ./9pm/9pm.py case/all.yaml
```
### Connecting to Infamy ### Connecting to Infamy
@@ -100,65 +115,76 @@ The test system runs in a Docker container, so to get a shell prompt in
*another terminal* you need to connect to that container. Infamy comes *another terminal* you need to connect to that container. Infamy comes
with a helper script for this: with a helper script for this:
$ ./test/shell ```
11:42:53 infamy0:test # $ ./test/shell
11:42:53 infamy0:test #
```
By default it connect to the latest started Infamy instance. If you for By default it connect to the latest started Infamy instance. If you for
some reason run multiple instances of Infamy the `shell` script takes an some reason run multiple instances of Infamy the `shell` script takes an
optional argument "system", which is the hostname of the container you optional argument "system", which is the hostname of the container you
want to connect to: want to connect to:
$ ./test/shell infamy2 ```
11:42:53 infamy2:test # $ ./test/shell infamy2
11:42:53 infamy2:test #
```
### Connecting to a DUT ### Connecting to a DUT
> [!TIP]
> The `console` script uses `telnet` to connect to a port forwarded to
> `localhost` by the Docker container. To exit Telnet, use Ctrl-] and
> then 'q' followed by enter. This can be customized in `~/.telnetrc`
All DUTs in a virtual Infamy topology are emulated in Qemu instances All DUTs in a virtual Infamy topology are emulated in Qemu instances
managed by qeneth. If you want to watch what's happening on one of the managed by qeneth. If you want to watch what's happening on one of the
target systems, e.g., tail a log file or run `tcpdump` during the test, target systems, e.g., tail a log file or run `tcpdump` during the test,
there is another helper script in Infamy for this: there is another helper script in Infamy for this:
$ ./test/console 1 ```
Trying 127.0.0.1... $ ./test/console 1
Connected to 127.0.0.1. Trying 127.0.0.1...
Connected to 127.0.0.1.
Infix OS — Immutable.Friendly.Secure v23.11.0-226-g0c144da (console) Infix OS — Immutable.Friendly.Secure v23.11.0-226-g0c144da (console)
infix-00-00-00 login: admin infix-00-00-00 login: admin
Password: Password:
.-------. .-------.
| . . | Infix OS — Immutable.Friendly.Secure | . . | Infix OS — Immutable.Friendly.Secure
|-. v .-| https://kernelkit.org |-. v .-| https://kernelkit.org
'-'---'-' '-'---'-'
Run the command 'cli' for interactive OAM Run the command 'cli' for interactive OAM
admin@infix-00-00-00:~$ admin@infix-00-00-00:~$
```
From here we can observe `dut1` freely while running tests. From here we can observe `dut1` freely while running tests.
> The `console` script uses `telnet` to connect to a port forwarded to
> `localhost` by the Docker container. To exit Telnet, use Ctrl-] and
> then 'q' followed by enter. This can be customized in `~/.telnetrc`
Like the `shell` script, `console` takes an optional "system" argument Like the `shell` script, `console` takes an optional "system" argument
in case you run multiple instances of Infamy: in case you run multiple instances of Infamy:
$ ./test/console 1 infamy2 ```
$ ./test/console 1 infamy2
...
```
You can also connect to the console of a DUT from within a `shell`: You can also connect to the console of a DUT from within a `shell`:
$ ./test/shell ```
11:42:54 infamy0:test # qeneth status $ ./test/shell
11:42:54 infamy0:test # qeneth console dut1 11:42:54 infamy0:test # qeneth status
login: admin 11:42:54 infamy0:test # qeneth console dut1
password: ***** login: admin
admin@infix-00-00-00:~$ password: *****
admin@infix-00-00-00:~$
> **Note:** disconnect from the qeneth console by using bringing up the ```
> old Telnet "menu" using Ctrl-], compared to standard Telnet this is
> the BusyBox version so you press 'e' + enter instead of 'q' to quit.
> [!TIP]
> Disconnect from the qeneth console by bringing up the old Telnet
> "menu" using Ctrl-], compared to standard Telnet this is the BusyBox
> version so you press 'e' + enter instead of 'q' to quit.
### Attaching to MACVLANs ### Attaching to MACVLANs
@@ -171,27 +197,32 @@ interactively inject traffic into the test setup.
First, connect to the Infamy instance in question: First, connect to the Infamy instance in question:
$ ./test/shell ```
11:43:19 infamy0:test # $ ./test/shell
11:43:19 infamy0:test #
```
Then, attach to the MACVLAN namespace by running the `nsenter` helper Then, attach to the MACVLAN namespace by running the `nsenter` helper
script from the test directory, supplying the base interface name as script from the test directory, supplying the base interface name as
the first argument: the first argument:
11:43:19 infamy0:test # ./nsenter d1b ```
11:43:20 infamy0(d1b):test # 11:43:19 infamy0:test # ./nsenter d1b
11:43:20 infamy0(d1b):test #
```
By default, an interactive shell is started, but you can also supply By default, an interactive shell is started, but you can also supply
another command: another command:
11:43:19 infamy0:test # ./nsenter d1b ip -br addr ```
lo UNKNOWN 127.0.0.1/8 ::1/128 11:43:19 infamy0:test # ./nsenter d1b ip -br addr
iface@if7 UP 10.0.0.1/24 fe80::38d0:88ff:fe77:b7cd/64 lo UNKNOWN 127.0.0.1/8 ::1/128
iface@if7 UP 10.0.0.1/24 fe80::38d0:88ff:fe77:b7cd/64
```
You can now freely debug the network activity of your test and the You can now freely debug the network activity of your test and the
responses from the DUT. responses from the DUT.
### Using the Python Debugger ### Using the Python Debugger
The built in `breakpoint()` function in Python is very useful when you The built in `breakpoint()` function in Python is very useful when you
@@ -202,13 +233,15 @@ Simply insert a call to `breakpoint()` at the point of interest in
your test and run it as normal. Once Python executes the call, it will your test and run it as normal. Once Python executes the call, it will
drop you into the Python debugger: drop you into the Python debugger:
11:42:58 infamy0:test # ./case/infix_dhcp/dhcp_basic.py ```
# Starting (2024-02-10 11:42:59) 11:42:58 infamy0:test # ./case/infix_dhcp/dhcp_basic.py
# Probing dut1 on port d1a for IPv6LL mgmt address ... # Starting (2024-02-10 11:42:59)
# Connecting to mgmt IP fe80::ff:fe00:0%d1a:830 ... # Probing dut1 on port d1a for IPv6LL mgmt address ...
ok 1 - Initialize # Connecting to mgmt IP fe80::ff:fe00:0%d1a:830 ...
> /home/jocke/src/infix/test/case/infix_dhcp/dhcp_basic.py(44)<module>() ok 1 - Initialize
(Pdb) > /home/jocke/src/infix/test/case/infix_dhcp/dhcp_basic.py(44)<module>()
(Pdb)
```
At this point you have full access to the test's state, but it is also At this point you have full access to the test's state, but it is also
an opportunity to inspect the state of the DUTs (e.g. via their an opportunity to inspect the state of the DUTs (e.g. via their
@@ -218,8 +251,9 @@ It is also possible to run a test under Pdb from the get-go, if you
want to setup breakpoints without modifying the source, or simply step want to setup breakpoints without modifying the source, or simply step
through the code: through the code:
11:42:58 infamy0:test # python -m pdb case/infix_dhcp/dhcp_basic.py ```
11:42:58 infamy0:test # python -m pdb case/infix_dhcp/dhcp_basic.py
```
### Deterministic Topology Mappings ### Deterministic Topology Mappings
@@ -230,34 +264,40 @@ between phyical nodes. In such cases, supplying a `PYTHONHASHSEED`
variable (set to any 32-bit unsigned integer) when launching the test variable (set to any 32-bit unsigned integer) when launching the test
environment will make sure that topology mappings are deterministic: environment will make sure that topology mappings are deterministic:
$ make PYTHONHASHSEED=0 test-sh ```
$ make PYTHONHASHSEED=0 test-sh
```
If a seed is not supplied, a random value is chosen. This seed is If a seed is not supplied, a random value is chosen. This seed is
logged by the `meta/reproducible.py` test case when running a test logged by the `meta/reproducible.py` test case when running a test
suite: suite:
$ make test ```
Info: Generating topology $ make test
Info: Generating node YAML Info: Generating topology
Info: Generating executables Info: Generating node YAML
Info: Launching dut1 Info: Generating executables
Info: Launching dut2 Info: Launching dut1
Info: Launching dut3 Info: Launching dut2
Info: Launching dut4 Info: Launching dut3
9PM - Simplicity is the ultimate sophistication Info: Launching dut4
9PM - Simplicity is the ultimate sophistication
Starting test 0002-reproducible.py Starting test 0002-reproducible.py
2024-05-03 10:40:30 # Starting (2024-05-03 10:40:30) 2024-05-03 10:40:30 # Starting (2024-05-03 10:40:30)
2024-05-03 10:40:30 # Specify PYTHONHASHSEED=3773822171 to reproduce this test environment 2024-05-03 10:40:30 # Specify PYTHONHASHSEED=3773822171 to reproduce this test environment
2024-05-03 10:40:30 ok 1 - $PYTHONHASHSEED is set 2024-05-03 10:40:30 ok 1 - $PYTHONHASHSEED is set
2024-05-03 10:40:30 # Exiting (2024-05-03 10:40:30) 2024-05-03 10:40:30 # Exiting (2024-05-03 10:40:30)
2024-05-03 10:40:30 1..1 2024-05-03 10:40:30 1..1
... ...
```
This is useful because this value can then be used to rerun a test (or This is useful because this value can then be used to rerun a test (or
the whole suite) with identical topology mappings: the whole suite) with identical topology mappings:
$ make PYTHONHASHSEED=3773822171 TESTS=case/ietf_system/hostname.py test ```
$ make PYTHONHASHSEED=3773822171 TESTS=case/ietf_system/hostname.py test
```
### Deterministic Transport Protocol ### Deterministic Transport Protocol
@@ -266,13 +306,16 @@ chosen randomly. If you supply a `PYTHONHASHSEED` as described above,
you get the same protocol used for that hash. But if you want to choose you get the same protocol used for that hash. But if you want to choose
the protocol, add extra arguments to Infamy: the protocol, add extra arguments to Infamy:
$ make INFAMY_EXTRA_ARGS="--transport=restconf" TESTS=case/ietf_system/hostname.py test ```
$ make INFAMY_EXTRA_ARGS="--transport=restconf" TESTS=case/ietf_system/hostname.py test
```
or, when running interactively: or, when running interactively:
$ make test-sh ```
09:08:17 infamy0:test # ./9pm/9pm.py -o"--transport=restconf" case/ietf_system/hostname.py $ make test-sh
09:08:17 infamy0:test # ./9pm/9pm.py -o"--transport=restconf" case/ietf_system/hostname.py
```
### Test specification ### Test specification
@@ -287,13 +330,13 @@ for example:
```python ```python
test.step("Set IPv4 address on the interface dut:cross") test.step("Set IPv4 address on the interface dut:cross")
test.step("Verify the IP address is set on dut:cross") test.step("Verify the IP address is set on dut:cross")
``` ```
where dut, cross and the IPv4 address could be found inside the
where *dut*, *cross* and the IPv4 address could be found inside the
logical topology for the test. logical topology for the test.
Each test case must begin with the test name followed by a empty line and Each test case must begin with the test name followed by a empty line
the description of the test. For example: and the description of the test. For example:
``` ```
""" """
@@ -305,32 +348,35 @@ Verify that it it possible to change hostname
The test specifaction can be genererated with: The test specifaction can be genererated with:
$ make test-spec ```
$ make test-spec
...
```
### Test Development ### Test Development
For adding a new test to the automated regression test suite, it's best For adding a new test to the automated regression test suite, it's best
to start by reviewing an existing test case. to start by reviewing an existing test case.
All tests are located in the `infix/test/case` repository and are All tests are located in the `infix/test/case` repository and are
grouped by the features they verify. For example, grouped by the features they verify. For example,
`infix/test/case/infix_services` contains tests for various Infix `infix/test/case/infix_services` contains tests for various Infix
services, such as LLDP and mDNS. services, such as LLDP and mDNS.
While test grouping is flexible, each test should be placed in a While test grouping is flexible, each test should be placed in a
logically relevant category. logically relevant category.
When creating a new test group, add it to `infix/test/case/all.yaml`, When creating a new test group, add it to `infix/test/case/all.yaml`, to
to enable it to run as a enable it to run as a [subset of the test
[subset of the test suite](#running-subsets-of-tests): suite](#running-subsets-of-tests):
``` ```
- name: infix-services - name: infix-services
suite: infix_services/infix_services.yaml suite: infix_services/infix_services.yaml
``` ```
A new test (e.g., lldp_enable_disable) should be added to the A new test (e.g., lldp_enable_disable) should be added to the
corresponding test group .yaml file, such as corresponding test group .yaml file, such as
`infix/test/cases/infix_services.yaml`: `infix/test/cases/infix_services.yaml`:
``` ```
@@ -338,21 +384,22 @@ corresponding test group .yaml file, such as
case: lldp_enable_disable/test.py case: lldp_enable_disable/test.py
``` ```
It is necessary to include the test in It is necessary to include the test in
`infix/test/case/infix_services/Readme.adoc` to ensure proper test `infix/test/case/infix_services/Readme.adoc` to ensure proper test
specification generation: specification generation:
``` ```
include::lldp_enable_disable/Readme.adoc[] include::lldp_enable_disable/Readme.adoc[]
``` ```
Each test case should have its own directory under, Each test case should have its own directory under,
`infix/test/case/infix_services`, containing: `infix/test/case/infix_services`, containing:
- `test.py` - the test script
- `topology.dot` - the logical topology definition.
When the [test specification](#test-specification) is generated, - `test.py` - the test script
`topology.svg` and `Readme.adoc` should also be created. - `topology.dot` - the logical topology definition.
When the [test specification](#test-specification) is generated,
`topology.svg` and `Readme.adoc` should also be created.
[9PM]: https://github.com/rical/9pm [9PM]: https://github.com/rical/9pm
[Qeneth]: https://github.com/wkz/qeneth [Qeneth]: https://github.com/wkz/qeneth
+15 -10
View File
@@ -9,33 +9,38 @@ These images also work with the Graphical Network Simulator ([GNS3][]),
which is a very user-friendly tool for playing around with simple to which is a very user-friendly tool for playing around with simple to
complex network setups, verifying interoperability between vendors, etc. complex network setups, verifying interoperability between vendors, etc.
QEMU QEMU
---- ----
> **Note:** installation for Debian/Ubuntu based systems: <kbd>sudo apt > [!TIP]
> install virt-manager</kbd> -- dependencies ensure the relevant Qemu > Installation for Debian/Ubuntu based systems can be done by "simply":
> packages are pulled in as well. Installing [virt-manager][virt] helps > <kbd>sudo apt install virt-manager</kbd> -- dependencies ensure the
> set up Qemu networking on your system. > relevant Qemu packages are pulled in as well. This trick, installing
> [virt-manager][virt], helps set up Qemu networking on your system.
A virtualized Infix x86_64 instance can easily be launched from a Linux A virtualized Infix x86_64 instance can easily be launched from a Linux
system, with [Qemu][] installed, by issuing: system, with [Qemu][] installed, by issuing:
./qemu.sh ```
$ ./qemu.sh
...
```
from an unpacked [release tarball][rels]. From a built source tree of from an unpacked [release tarball][rels]. From a built source tree of
Infix the same functionality is bundled as: Infix the same functionality is bundled as:
make run ```
$ make run
...
```
To change settings, e.g. networking, <kbd>make run-menuconfig</kbd>, or To change settings, e.g. networking, <kbd>make run-menuconfig</kbd>, or
from a pre-built Infix release tarball, using <kbd>./qemu.sh -c</kbd> from a pre-built Infix release tarball, using <kbd>./qemu.sh -c</kbd>
The Infix test suite is built around Qemu and [Qeneth][qeth], see: The Infix test suite is built around Qemu and [Qeneth][qeth], see:
* [Regression Testing with Infamy](testing.md) * [Regression Testing with Infamy](testing.md)
* [Infamy Docker Image](https://github.com/kernelkit/infix/blob/main/test/docker/README.md) * [Infamy Docker Image](https://github.com/kernelkit/infix/blob/main/test/docker/README.md)
GNS3 GNS3
---- ----