Data provisioning¶
Overview¶
Welma enables native management of product provisioning data (such as serial numbers, hardware revisions, MAC addresses, etc.) through data-store, a data provisioning implementation..
Data provisioning is a management system that handles structured data blocks across different storage backends (such as eMMC, EEPROM, files or block devices) while providing data integrity features.
Features:
- Small storage footprint (minimum size 17 bytes)
- Make it read-only after provisioning completed
- Protection against hardware reset (data does not get corrupted)
- Several values can be set atomically
- Values are octet strings, with optional integer conversion
- D-Bus interface
Runtime architecture¶
On the embedded Linux system, the provisioning data is accessible via the
dsctl
tool provided by the data-store
package. This tool can be used in two
different modes:
-
Base mode: Compiled into
dsctl.base
binary. It Provides direct access to the backend via the access management library (libdsio.so
). Welma usese this mode in theinitramfs
context to setup themachine-id
. -
D-Bus mode: Compiled into
dsctl.dbus
binary. It provides acces to the backend via a dedicated D-Bus server allows all access to the backend to be centralized in a single process, which protects the backend from concurrent access. This mode is available in the root filesystem by default.
Yocto configuration¶
The definition of the data blocks layout and the variables contained therein is managed during compilation using a YAML file. To customize the layout, simply provide a suitable description file.
Description file¶
The description file defines data block structure and storage configuration. It must contain at least one block. Each block must have a unique name can be configured using the following options:
type
: The block type. Onlystatic
is supportedbackend
: Defines the runtime device backend pathbackend-offset
: Defines the offset where Data store is located inside the backendbackend-offset-copy
(optional): Defines the offset of block copy inside the backendoptions
(optional): Defines the verification options. Onlycrc
andnone
are supported. Default tocrc
data
: Defines the variables inside the current block as a list of<name>: <size>
with sizes specified in bytes
Naming convention¶
Blocks must be defined under the appropriate blocks
section. Neither block names nor
variable names may contain spaces, periods, colons, quotation marks, equal signs,
backslashes, or null bytes. Variable sizes are restricted to decimal and hexadecimal
formats.
Additionally, environment variables can be used within the data mapping file to provide flexibility in configuration.
The default description file in welma is defined as follows:
blocks:
- welma:
type: static
backend: '${BOOT_DEV_PATH}'
backend-offset: 0x200000
options: 'crc'
data:
machine-id: 32
Note
To ensure the machine ID is managed by data-store within the initramfs
,
Welma defines a default welma
block that includes the machine-id
variable.
If you intend to customize this setup, please make sure to update the
initramfs
with the corresponding block and variable
Block Structure¶
Each static block stored in the backend follows a defined structure, which is organized as follows:
Offset | Size | Field | Description |
---|---|---|---|
0x00 | 8 | Magic Header | "DSHEADER" (ASCII) |
0x08 | 1 | Closed Flag | 0x49 = closed, other = open |
0x09 | 2 | Data store size | Total size block variables (N) |
0x0b | 1 | Reserved | Not used |
0x0c | N | Variable Data | Sequential variable storage |
N+0x0c | 4 | CRC32 Checksum | If enabled |
Usage¶
The data-store
implementation of data provisioning includes the dsctl
tool,
which allows interaction with data stored in the backends.
dsctl
API¶
Usage:
build/dsctl.base COMMAND [OPTIONS] [BLOCK[.VARIABLE[=VALUE]]] [ARGUMENTS]
Commands:
init <block> [--force|-f] [--backend|-b <backend>]
info [<block>[.<variable>]] [--backend|-b <backend>]
get <block>.<variable>[:int] [--backend|-b <backend>]
set <block>.<variable>[:int]=<value> [--backend|-b <backend>] [--force|-f]
close <block> [--backend|-b <backend>]
Arguments:
-b | --backend <path> : Specify the backend device to use. Only on base mode
-f | --force : Force write operation even if the block is corrupted
-h | --help : Show usage information
Commands¶
-
init
: Initialize an empty block in the backend (values set to 0). If the block contains valid (uncorrupted) data, the--force
flag must be used to overwrite the block, otherwise,DSIO_UNAUTHORIZED_OPERATION
error is returned -
info
: Display information about blocks and variables -
get
: Retrieve the value of a variable in a block. It supports reading only one variable at a time. The:int
keyword could be used to read a stored integer value (Only for data store sizes up to 8 bytes). -
set
: Set the value of a variable in a block. Several variables within the same block can be written in a single command. If the block is corrupted, the--force
flag must be used, otherwise,DSIO_UNAUTHORIZED_OPERATION
error is returned -
close
: Close a specific block. No writing (set and init) will be allowed. Used only for blocks with valid (uncorrupted) content.
D-Bus API¶
The data-store
daemon exposes a D-Bus API, described as follow:
node /com/witekio/datastore {
interface com.witekio.datastore.Manager {
methods:
Close(in s block);
Init(in s block,
in i force);
Get(in s block,
in s variable,
out ay value);
Set(in s block,
in a(siay) variables,
in i force);
GetBlocks(out as blocks);
Info(in s block,
out s name,
out s backend,
out a(st) data,
out t offset,
out t offset_copy,
out i data_count,
out i type,
out i mode,
out i options);
GetVarInfo(in s block,
in s variable,
out t size);
signals:
properties:
};
}
Note
the --backend
option is only supported by the base mode. D-Bus implementation
always uses the default backend listed the YAML description file
Usage example¶
In this example, we define a read-only block named config
, which contains both
a serial number and a numeric identifier. To do this, we follow these steps:
-
Add the new block under the blocks section in the YAML description file
-
Build and install the new you image
On the running image:
-
check the available blocks
-
Initialize the
config
block in the backend -
In this step, verify that the config block is defined as a
read-write
mode block -
Set a value for each variable
-
Close the block to make it
read-only
-
Applications can use D-Bus API or
dsctl
tool to readconfig
variables
Once the config block is closed, no further modifications can be made to it through
data-store
tools.