Skip to content

Vital Product Data

Infix can source Vital Product Data (VPD) from EEPROMs containing an ONIE TLV. The load bearing information from VPDs, used by Infix by default, is:

  1. Base (chassis) MAC address of the system
  2. Factory default admin password hash

Additionally, every VPD is listed as a separate component in the ietf-hardware model, in which Infix exports all available attributes to the user. This is useful to read out exact hardware revisions of each board making up a system, figure out if a system belongs to a particular production batch, etc.

Device Tree Bindings

The system finds its VPDs through the vpds property of the /chosen/infix node in the device tree (DT), a list of phandles to EEPROMs with an ONIE TLV layout. Each EEPROM is named with an infix,board property, and may be marked infix,trusted:

/ {
    chosen {
        infix {
            vpds = <&vpd_cpu &vpd_product>;
        };
    };
};

&i2c0 {
    vpd_product: eeprom@50 {
        compatible = "atmel,24c02";
        reg = <0x50>;

        infix,board = "product";
        infix,trusted;

        nvmem-layout {
            compatible = "onie,tlv-layout";

            base_mac: mac-address {
                #nvmem-cell-cells = <1>;
            };
        };
    };
};

Every VPD is listed in the ietf-hardware model as a component named vpd-<board>, e.g., vpd-product for the example above.

VPD File on the Aux Partition

Boards without a VPD EEPROM, such as single board computers, boot with a random MAC address on every port and the vendor's default address on every WiFi radio. Two such boards of the same model cannot even talk to each other over WiFi, since both radios claim the same address.

Such a board can be given an identity by storing an ONIE TLV as /mnt/aux/vpd.bin. The boot loader hands the file to the system, which reads it like any other VPD. The onieprom tool encodes the JSON form described below:

echo '{"mac-address":"02:00:00:ba:01:00","serial-number":"banana1","vendor":"SinoVoip Co., Ltd.","product-name":"BPI-R3"}' \
  | onieprom -e > /mnt/aux/vpd.bin

The file survives upgrades, and removing it returns the board to random addresses on the next boot. A VPD read this way is never trusted, so it can only provide identity, never the factory password. The ports get their addresses from its base MAC address, each with a fixed offset given by the device tree, and WiFi interfaces derive theirs from the base MAC as described in WiFi.

This is currently supported on the Banana Pi BPI-R3 family and the Acer Connect Vero W6m.

Product VPD

The VPD named product describes the device as a whole. Its attributes are used for the following, falling back to other sources when an attribute is missing:

Key Used for Fallback
"vendor" mfg-name of the mainboard component Vendor of DT compatible
"product-name" model-name of the mainboard component DT model property
"part-number" hardware-rev of the mainboard component None
"serial-number" serial-num of the mainboard component DT serial-number property
"mac-address" Base (chassis) MAC address, see below Lowest MAC address of all interfaces

The base MAC address is the phys-address of the mainboard component. It is also what the chassis option of an interface's custom-phys-address refers to, see Common Interface Settings, and the source of the %m format specifier in the hostname, which the factory configuration uses to give each device a unique name, e.g., example-c0-ff-ee.

The kernel sets the MAC address of each Ethernet port from the nvmem-cells property of its device tree node, which can refer to the mac-address cell of the product VPD, plus an offset:

&eth0 {
    nvmem-cells = <&base_mac 1>;
    nvmem-cell-names = "mac-address";
};

Factory Password

The factory default admin password hash, the pwhash extension below, is read from the first VPD marked infix,trusted that has one, which need not be the product VPD. It takes precedence over a factory-password-hash property in the /chosen/infix node. Without either, the system reports a critical bootstrap error.

Virtual Machines

When running in QEMU, the product VPD is read from the opt/vpd firmware configuration file, and is always trusted. Without that file the password defaults to admin, and the base MAC address is the lowest port MAC address minus one.

JSON Encoding

To make EEPROM binary generation less cumbersome, Infix defines a JSON encoding of an ONIE TLV, and provides a tool, onieprom, to translate from one encoding to another. I.e. a JSON object can be translated to its binary equivalent, and vice versa.

A mapping between TLV attribute IDs and JSON keys is defined, using the Linux kernel driver as a reference:

TLV ID Description Key Type
0x21 Product Name "product-name" String
0x22 Part Number "part-number" String
0x23 Serial Number "serial-number" String
0x24 MAC #1 Base "mac-address" String ("c0:ff:ee:00:00:00")
0x25 Manufacture Date "manufacture-date" String ("MM/DD/YYYY HH:NN:SS")
0x26 Device Version "device-version" Integer (u8)
0x27 Label Revision "label-revision" String
0x28 Platform Name "platform-name" String
0x29 ONIE Version "onie-version" String
0x2a Num MACs "num-macs" Integer (u16)
0x2b Manufacturer "manufacturer" String
0x2c Country Code "country-code" String (ISO 3166-1 2-byte code)
0x2d Vendor "vendor" String
0x2e Diag Version "diag-version" String
0x2f Service Tag "service-tag" String
0xfd Vendor Extension "vendor-extension" List of extensions (see below)

The JSON encoding of a TLV is a single JSON object with an arbitrary subset of the attributes from the list above.

Example:

{
    "product-name": "Wacky Widget",
    "serial-number": "#1",
    "manufacture-date": "02/13/2024 11:29:52"
}

Vendor Extensions

As the specification explicitly mentions the option of supplying multiple vendor extensions, possibly multiple ones of the same type, the JSON chosen encoding is a list, where each element is itself a list of exactly two elements:

Element # Type
1 Integer (u32, IANA enterprise number)
2 String (UTF-8 encoded extension data)

The format of the extension data is defined by the entity indicated by the IANA enterprise number. Restricting extension data to UTF-8 encoded strings is a decision imposed by Infix; the ONIE specification allows for arbitrary binary data.

Example:

{
    ...
    "vendor-extension": [
        [ 12345, "my extension data" ]
    ]
}

Infix Specific Extensions

Kernelkit's IANA enterprise number is 61046, under which any extensions required by Infix are stored. The only valid extension data that may be stored under this number is documented in this section. If other device specific data needs to be stored in a VPD, you must associate that with an enterprise number under our control.

Every Kernelkit extension must be a valid JSON object containing an arbitrary subset of the following attributes:

Key Value Description
"pwhash" String (output of mkpasswd(1)) Factory default password for admin

Since the extension is itself stored in a JSON document, it has to be appropriately quoted.

Example:

{
    ...
    "vendor-extension": [
        [ 61046, "{\"pwhash\":\"$6$9rufAxdqCrxrwfQR$G0l9cTVlu/vOhxgo/uMKfRDOmZRd5XWF3vKr5da6qYoxuTJBS/Pl9K.5lrabWoWFFc.71yFMaSlZz0O8FtAtl.\"}" ]
    ]
}

Creating and Parsing ONIE EEPROM Binaries

usage: onieprom [-h] [-e] [-d] [infile] [outfile]

positional arguments:
  infile
  outfile

options:
  -h, --help    show this help message and exit
  -e, --encode  Encode JSON input to binary output
  -d, --decode  Decode binary input to JSON output

To convert a compatible JSON document (using the first example above) to its binary equivalent, we ask onieprom to encode it for us:

~$ onieprom -e example.json >example.bin
~$ hexdump -C example.bin
00000000  54 6c 76 49 6e 66 6f 00  01 00 2d 25 13 30 32 2f  |TlvInfo...-%.02/|
00000010  31 33 2f 32 30 32 34 20  31 31 3a 32 39 3a 35 32  |13/2024 11:29:52|
00000020  21 0c 57 61 63 6b 79 20  57 69 64 67 65 74 23 02  |!.Wacky Widget#.|
00000030  23 31 fe 04 dd 69 88 97                           |#1...i..|
00000038

We can also run the process in reverse, to inspect the contents of a binary in its equivalent JSON representation:

~$ onieprom -d example.bin >example-again.json
~$ jq . example-again.json
{
  "manufacture-date": "02/13/2024 11:29:52",
  "product-name": "Wacky Widget",
  "serial-number": "#1"
}