Привет, Хабр! Меня зовут Александр Амелькин. Я технический эксперт департамента разработки BIOS и BMC в компании YADRO, мейнтейнер проекта ipmitool, а также автор и мейнтейнер проекта frugen / libfru, о котором и хочу сегодня рассказать, тем более что совсем недавно я выпустил новую версию 3.0 этого пакета.
Что такое FRU
Аббревиатура FRU расшифровывается как Field Replaceable Unit и изначально обозначает компонент сервера, который можно менять непосредственно «в полях», то есть у заказчика, без необходимости отвозить весь сервер в сервисный центр на обслуживание. Помимо FRU существует также и CRU (Customer-Replaceable Unit) — это компонент, замена которого может производиться силами самого клиента.
Но это классические определения, которыми пользуются сотрудники сервисных департаментов. Разработчики встроенного ПО серверов используют аббревиатуру FRU в несколько ином смысле.
Наша компания разрабатывает серверы и системы хранения данных, а одна из важнейших задач для их встроенного ПО — это инвентаризация компонентов оборудования. Поэтому возникает необходимость где-то и в каком-то виде хранить эту информацию, записывать ее туда при производстве и в дальнейшем отображать в интерфейсах системы.
Одним из классических методов решения этой задачи, особенно для систем на базе архитектуры x86, является запись такой информации в микросхемы EEPROM, располагаемые на платах каждого подлежащего учету FRU и CRU. Такой подход используется как для компонентов, выпускаемых непосредственно вендором вычислительной системы, так и в ряде случаев для сторонних общеупотребимых компонентов, таких как блоки питания, дисковые накопители, модули памяти или различные адаптеры периферийных устройств.
За время становления индустрии вычислительных систем, было создано много разных форматов хранения данных в таких EEPROM, часть из них была строго специфична для конкретных производителей или даже моделей устройств, но часть, к счастью, была и стандартизована. К стандартизованным форматам можно отнести широко известный JEDEC SPD (JESD400-5C, JESD21-C и другие), IBM VPD, а также Intel IPMI FRU Information Storage. Последний формат используется для передачи информации о FRU как часть спецификации протокола IPMI, а также является частью спецификации Intel CRPS (документ Intel #573090) для серверных блоков питания и спецификации NMVe Management Interface для твердотельных накопителей.
Именно Intel IPMI FRU Information Storage, а также саму микросхему, содержащую данные в этом формате, в среде разработчиков BMC и BIOS принято называть словом FRU. С этим форматом и работает пакет libfru / frugen.
Какая информация есть во FRU EEPROM?
Набор возможных данных, хранимых во FRU EEPROM, определяется спецификацией Intel IPMI FRU Information Storage. Вся информация разделена на пять областей, присутствие каждой из которых не обязательно и определяется информацией в общем заголовке FRU EEPROM, где размещены указатели на данные каждой из них в следующем порядке:
1. Область для внутреннего использования (Internal Use Area) — ее
содержимое не описано спецификацией. Предполагается, что эта часть EEPROM может использоваться программным обеспечением BMC или другого контроллера на плате для хранения какой-то служебной информации (например, внутренних состояний).
2. Область информации о шасси (Chassis Information Area) — здесь содержится базовая информация о «корпусе» или «шасси» устройства, описываемого этим FRU EEPROM. Основным параметром тут является «тип шасси», который представляет собой целое число, выбираемое согласно спецификации SMBIOS (см. DMTF DSP0134, Table 17). Например, значение 0x17 соответствует типу «Rack Mount Chassis». Также в этой области может содержаться информация о серийном номере шасси и его артикуле (part number).
Создатели спецификации предполагали, что эта область присутствует на главной плате всего изделия и на любых корпусированных компонентах, таких как блоки питания или дисковые накопители, но не все производители и не всегда придерживаются этого правила.
3. Область информации о плате (Board Information Area) может содержать информацию непосредственно о той плате, на которой установлена эта микросхема FRU EEPROM. Среди этой информации могут быть: дата и время изготовления платы, название производителя, продуктовое название платы, серийный номер, артикул, а также «идентификатор файла», из которого собрана информация о плате. Предполагается, что эта область присутствует в любой FRU EEPROM, так как эта микросхема в любом случае располагается на какой-то плате. Однако спецификация допускает и отсутствие этой области. Такое может пригодиться, если, например, микросхема FRU EEPROM на плате не одна. Или если она съемная и описывает только шасси и/или продукт. В последнем случае ее можно снять и переставить на другую плату, если первая вышла из строя.

4. Область информации о продукте (Product Information Area) обычно соседствует с областью информации о шасси и располагается в главной FRU EEPROM — на главной плате изделия или на отдельном переставляемом модуле, подключенном к этой плате. Эта область может содержать информацию об изделии в целом: название производителя изделия, название самого изделия, его артикул или номер модели, версию, серийный номер изделия, а также метку принадлежности (asset tag, например, «Accounting Server») и «идентификатор файла», из которого собрана информация об изделии.
5. Область множественных записей (Multirecord Area) содержит различные записи, которые не удалось однозначно соотнести ни с одной из предыдущих информационных областей. Например, тут могут содержаться входные и выходные параметры блока питания или конвертера напряжения, уникальный идентификатор системы (UUID), информация о URL управляющего ПО, информация о емкости NVMe накопителя, и тому подобное. Формат этих записей описывается как самой спецификацией IPMI FRU Information Storage Definition, так и другими спецификациями, такими как ASF или NVME-MI. Также здесь есть место и для OEM-записей (типы с 0xC0 по 0xFF), формат которых каждый производитель определяет самостоятельно.
Отмечу, что каждая «информационная» область (шасси, платы, продукта) может содержать еще и набор произвольных (custom) полей, определяемых производителем оборудования.
Где взять FRU?
Обычно содержимое FRU для различных компонентов сервера доступно в декодированном виде при помощи утилиты ipmitool и выглядит примерно так:
# ipmitool fru print
FRU Device Description : Builtin FRU Device (ID 0)
Chassis Type : Rack Mount Chassis
Chassis Part Number : Y05X82U2S124A
Board Mfg Date : Tue Apr 30 05:31:00 2024 UTC
Board Mfg : YADRO
Board Product : VEGMAN Motherboard
Board Serial : Y0VCB3075Y00X
Board Part Number : MBDX86784004B
Board Extra : 0100a0c5f21296e7
Board Extra : 0101a0c5f21296e8
Board Extra : 0120a0c5f21296e9
Board Extra : 0121a0c5f21296ea
Board Extra : 0122a0c5f21296eb
Board Extra : 0123a0c5f21296ec
Board Extra : 0124a0c5f21296ed
Product Manufacturer : YADRO
Product Name : VEGMAN R220 G2
Product Part Number : ASMVEG780505B1
Product Serial : Q280835376
FRU Device Description : Riser A3 (1x16 + (ID 80)
Board Mfg Date : Fri Sep 1 09:09:00 2023 UTC
Board Mfg : YADRO
Board Product : Riser A3 (1x16 + 2x8 + 2 rear BPL) 2U
Board Serial : Y1E3B3PKLI008
Board Part Number : RSRPCI781009B
FRU Device Description : 2xSFF rear backp (ID 88)
Board Mfg Date : Mon Sep 4 09:51:00 2023 UTC
Board Mfg : YADRO
Board Product : 2xSFF rear backplane 2U
Board Serial : Y1UUB3PKLI012
Board Part Number : BPLUNI781013B
FRU Device Description : U1A-D2000-J-13 (ID 96)
Product Manufacturer : ASPOWER
Product Name : U1A-D2000-J-13
Product Part Number :
Product Version : 1.0
Product Serial : D012000H7U1748
FRU Device Description : PM9A3 (ID 110)
Product Manufacturer : Samsung
Product Name : PM9A3
Product Part Number : MZQL23T8HCLS-00A07
Product Serial : S64HNE0T437416
FRU Device Description : 24xSFF backplane (ID 141)
Board Mfg Date : Mon Sep 4 07:15:00 2023 UTC
Board Mfg : YADRO
Board Product : 24xSFF backplane
Board Serial : Y1URA3PKLI002
Board Part Number : BPLUNI782016A
…
Аналогичным образом, но используя команду ‘ipmitool fru read’, можно считать с доступного вам по IPMI сервера и бинарное содержимое имеющихся там FRU EEPROM, хотя разработчики, конечно, обычно используют другие методы.
Зачем же нужны и что могут frugen и libfru?
Хоть утилита ipmitool и позволяет в некотором виде декодировать и даже ограниченно модифицировать данные FRU, ее функциональность в этой части достаточно ограничена и оставляет желать много лучшего. К тому же, эта утилита предназначена по большей части для администраторов серверов, а не для их производителей и крайне неудобна для решения задач последних.
Утилита frugen и библиотека libfru были задуманы мною в далеком 2016 году как средство с открытым исходным кодом для генерации бинарных образов FRU EEPROM именно для производителей серверных систем. С момента создания и до версии 3.0, доступной на момент публикации статьи, они прошли большой путь и обзавелись внушительным количеством возможностей, которые облегчают повседневные задачи производителей оборудования, таких как компания YADRO. До версии 3.0 библиотека libfru была слабо пригодна для использования вне утилиты frugen и предполагала глубокое знание пользователем внутреннего устройства формата IPMI FRU EEPROM. Со временем стало очевидно, что существует ряд задач в рамках разработки BMC, для решения которых пригодилась бы именно отдельная самостоятельная библиотека. Поэтому код библиотеки был практически полностью переписан по сравнению с предыдущей версией 2.1, в результате чего интерфейс библиотеки, как я надеюсь, стал гораздо более дружелюбным и легким в использовании. К тому же, в версии 3.0 я постарался максимально тщательно снабдить все функции API библиотеки подробным описанием в формате doxygen.
Увы, пока что документация недоступна в готовом виде ни по какому адресу в интернете, но вы всегда можете собрать ее самостоятельно. Инструкции по сборке есть в репозитории frugen. В дальнейшем я планирую выложить документацию к последней версии на сайт проекта.
libfru
Библиотека libfru 3.0 является частью утилиты frugen 3.0, а также может использоваться отдельно для работы с данными FRU EEPROM. Она написана на языке C таким образом, чтобы максимально абстрагировать пользователя от внутреннего устройства бинарного формата FRU EEPROM, где это возможно, но при этом всё же оперирует понятиями «областей», «полей» и «записей».
Итак, что же умеет libfru 3.0 ? Удобнее всего представить возможности библиотеки в виде списка:
-
Чтение и декодирование бинарных образов FRU EEPROM как из файла, так и из буфера в памяти:
Декодирование всех стандартных «информационных» областей (шасси, платы, продукта) со всеми стандартными и дополнительными полями.
Все поля декодируются из любого стандартного формата: binary, 6-bit ASCII, BCD+, text. Единственным ограничением на данный момент является отсутствие поддержки для формата text иных кодов языка, кроме стандартного английского (ASCII+Latin1), но, честно говоря, мне пока не встречались устройства, которые бы использовали другие коды языка во FRU EEPROM.Декодирование области для внутреннего использования в виде текстовой строки шестнадцатеричных символов (hex string). Вероятно, в будущем добавится и возможность вытаскивать эту область в виде бинарного буфера, если такая необходимость будет у пользователей библиотеки.
-
Декодирование области множественных записей (Multirecord Area). В библиотеке заложена возможность полноценного декодирования с разложением на отдельные поля всех стандартных типов записей, но на данный момент реализовано только:
Декодирование всех подтипов записей типа Management Access Record;
Декодирование любых других типов записей в виде сырых («raw») данных.
-
Простая модификация декодированной FRU:
Установка новых значений стандартных и дополнительных (custom) полей как из текстовой или hex-строки, так и из двоичного буфера;
Возможность сохранения типа кодирования данных при установке нового значения из текстовой строки (при условии совместимости диапазона символов);
Добавление, замена и удаление как записей в списках дополнительных (custom) полей информационных областей, так и элементов «области множественных записей». Возможно добавление в начало или конец списка, а также замена или вставка записи по определенному индексу.
Кодирование бинарных образов FRU EEPROM из созданной или модифицированной пользователем структуры в бинарный буфер в памяти или в файл. Поддерживаются все те же функции с теми же ограничениями, что и для декодирования.
Пример использования
Предположим, мы хотим написать утилиту, которая будет менять серийный номер платы в указанном файле на значение, заданное в командной строке. Это можно реализовать следующим образом (при условии, что библиотека установлена и доступна по стандартным путям):
#include <fru.h>
#include <fru_errno.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
fru_t * fru;
if (argc < 2) {
printf("Usage: frumod <frufile> <new_serial>\n");
return 1;
}
// Load from file, don't use preallocated template structure,
// don't use any quirks/workarounds on load, bail out on any
// errors
fru = fru_loadfile(NULL, argv[1], FRU_NOFLAGS);
// Handle errors in the most primitive way
if (!fru) {
// For more sophisticated error handling, see fru_perror()
// in frugen.c
if (fru_errno.code == FEGENERIC) {
perror("Error");
}
else {
fprintf(stderr, "FRU Error: %s", fru_strerr(fru_errno));
}
return 1;
}
// Set the new value, preserve the original encoding type
// or fail
if (!fru_setfield(&fru->product.serial,
FRU_FE_PRESERVE, argv[2]))
{
// Handle error here
return 1;
}
// Save back into the same file
if (!fru_savefile(argv[1], fru)) {
// Handle errors here
return 1;
}
}
Скомпилировав эту программу под именем frumod, мы сможем легко менять серийный номер в образе FRU перед записью его в EEPROM:
$ ./frumod my_eeprom.bin 1234-NEW-SERIAL-5678
Впрочем, это просто пример того, как легко написать код для работы с FRU при помощи libfru. В реальной жизни задачу по изменению серийного номера или любых других данных гораздо проще будет решить, используя готовую утилиту frugen.
frugen
Утилита frugen 3.0 — это, фактически, обертка вокруг библиотеки libfru 3.0, позволяющая использовать последнюю напрямую из командной строки без необходимости писать какие-то программы. Эта утилита на данный момент решает большинство задач нашего производства и сервиса по созданию и модификации FRU EEPROM.
Помимо функций, описанных выше, которые реализует сама библиотека libfru, утилита также позволяет:
Читать шаблон FRU из файла в формате JSON или из бинарного файла образа FRU EEPROM.
Модифицировать или добавлять отдельные поля шаблона по данным из командной строки.
-
Записывать модифицированные данные FRU в файлы следующих форматов:
бинарный FRU EEPROM,
JSON-шаблон,
простой текст — для удобного просмотра пользователем.
Утилита всегда требует указания имени выходного файла, но для вывода на стандартное устройство вывода (консоль) можно указать в качестве имени файла знак минус (-). Если формат вывода не указан явно, то для вывода в файл по умолчанию выбирается бинарный формат, а для вывода на консоль, в зависимости от наличия поддержки JSON, выбирается либо формат JSON, либо простой текст. Поддержка JSON определяется при компиляции опцией cmake ENABLE_JSON, которая по умолчанию устанавливается в ‘yes’ при наличии установленной библиотеки json-c.
Ниже я приведу несколько примеров использования утилиты для решения типичных задач производства и сервиса.
Декодирование и просмотр образа FRU EEPROM
$ frugen -r eeprom_dump.bin -o text -
=== Chassis Information Area ===
Chassis Type: 23
Part Number: [6bitascii] "CHSPN01020345"
Serial Number: [ text] ""
=== Board Information Area ===
Language Code: 25
Manufacturing date/time: 20/02/2025 01:57 MSK
Manufacturer: [6bitascii] "SuperManufacturer"
Product Name: [ text] "SuperComponentBoard"
Serial Number: [6bitascii] "SN12345678"
Part Number: [6bitascii] "MBDPN012345A"
FRU File ID: [ text] ""
Custom 1: [ binary] "123456789"
Custom 2: [ binary] "12345678A"
=== Product Information Area ===
Language Code: 25
Manufacturer: [6bitascii] "SuperManufacturer"
Product Name: [ text] "SuperProduct"
Part/Model Number: [6bitascii] "PRODPN123456ABC"
Version: [ text] ""
Serial Number: [ text] "PSN743653487"
Asset Tag: [ text] ""
FRU File ID: [ text] ""
=== Multirecord Area ===
#1: Management Access Record (0x03)
Subtype 7: System Unique ID (uuid)
Data : 3C9597D8572259488A82ECB489847AF8
Создание образа FRU EEPROM из шаблона
Пример шаблона можно найти в файле example.json в репозитории frugen.
$ frugen -j my_template.json -o binary my_fru_image.bin
В этом примере все поля будут без каких-либо изменений взяты из файла my_template.json и записаны в двоичном формате в файл my_fru_image.bin, пригодный для записи в EEPROM при помощи программатора или внутрисистемным способом.
Если в шаблоне присутствует область информации о плате (объект ‘board’), но не указана дата производства платы (свойство ‘date’), то в выходной файл будет записана текущая дата и время.
Создание образа FRU EEPROM из шаблона c модификацией
$ frugen -j my_template.json -u \
-s board.serial=”1234-NEW-SERIAL-5678” \
-o binary my_fru_image.bin
В этом примере все поля будут взяты из файла my_template.json, затем серийный номер платы будет изменен, а результат записан в двоичном формате в файл my_fru_image.bin, пригодный для записи в EEPROM при помощи программатора или внутрисистемным способом.
При этом если в шаблоне не указана дата производства платы (board.date), то и в выходном файле дата не будет указана, а точнее — будет указана «неуказанная» дата (за счет параметра ‘-u’).
Это типичная задача, решаемая при производстве новых изделий.
Замена дополнительного поля в образе FRU EEPROM
$ frugen -r eeprom_dump.bin \
-s product.custom2=”New_custom_value” \
-o binary new_eeprom_dump.bin
В этом примере все поля будут взяты из двоичного файла eeprom_dump.bin, затем дополнительное поле 2 (нумерация с 1) в области информации об изделии будет изменено на указанное значение, а результат изменений будет записан в двоичном формате в файл new_eeprom_dump.bin, пригодный для записи в EEPROM при помощи программатора или внутрисистемным способом.
Это типичная задача, решаемая при обслуживании изделий «в полях» или в сервисном центре сотрудниками сервисных подразделений.
Заключение
Надеюсь, эта статья окажется полезной для тех коллег, которые занимаются разработкой и производством вычислительной техники как в нашей стране, так и за ее пределами.
Я всегда рад услышать конструктивные замечания и предложения по улучшению, которые вы можете направлять непосредственно через интерфейсы задач и пулл-реквестов на странице проекта.
Большое спасибо за внимание.